about summary refs log tree commit diff
path: root/src/tools/clippy/tests/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/tests/ui')
-rw-r--r--src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs61
-rw-r--r--src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr147
-rw-r--r--src/tools/clippy/tests/ui/approx_const.rs60
-rw-r--r--src/tools/clippy/tests/ui/approx_const.stderr130
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.rs7
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.stderr27
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.rs29
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.stderr84
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed21
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs21
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.stderr58
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.rs55
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.stderr146
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_bool.rs25
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_bool.stderr35
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_fence.rs20
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_fence.stderr19
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_int.rs86
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_int.stderr163
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_ptr.rs27
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_ptr.stderr35
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_uint.rs86
-rw-r--r--src/tools/clippy/tests/ui/atomic_ordering_uint.stderr163
-rw-r--r--src/tools/clippy/tests/ui/attrs.rs43
-rw-r--r--src/tools/clippy/tests/ui/attrs.stderr24
-rw-r--r--src/tools/clippy/tests/ui/author.rs4
-rw-r--r--src/tools/clippy/tests/ui/author.stdout14
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.rs16
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout13
-rw-r--r--src/tools/clippy/tests/ui/author/call.rs4
-rw-r--r--src/tools/clippy/tests/ui/author/call.stdout16
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.stdout62
-rw-r--r--src/tools/clippy/tests/ui/author/if.rs10
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout31
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.rs14
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.stdout14
-rw-r--r--src/tools/clippy/tests/ui/author/matches.rs13
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout33
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs8
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs6
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs58
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/option_helpers.rs51
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs22
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/use_self_macro.rs15
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs21
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.rs64
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr63
-rw-r--r--src/tools/clippy/tests/ui/bit_masks.rs63
-rw-r--r--src/tools/clippy/tests/ui/bit_masks.stderr110
-rw-r--r--src/tools/clippy/tests/ui/blacklisted_name.rs40
-rw-r--r--src/tools/clippy/tests/ui/blacklisted_name.stderr88
-rw-r--r--src/tools/clippy/tests/ui/block_in_if_condition.fixed75
-rw-r--r--src/tools/clippy/tests/ui/block_in_if_condition.rs75
-rw-r--r--src/tools/clippy/tests/ui/block_in_if_condition.stderr36
-rw-r--r--src/tools/clippy/tests/ui/block_in_if_condition_closure.rs48
-rw-r--r--src/tools/clippy/tests/ui/block_in_if_condition_closure.stderr24
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.fixed129
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.rs129
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.stderr112
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs99
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.stderr26
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs85
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr131
-rw-r--r--src/tools/clippy/tests/ui/box_vec.rs32
-rw-r--r--src/tools/clippy/tests/ui/box_vec.stderr11
-rw-r--r--src/tools/clippy/tests/ui/builtin-type-shadow.rs9
-rw-r--r--src/tools/clippy/tests/ui/builtin-type-shadow.stderr26
-rw-r--r--src/tools/clippy/tests/ui/bytecount.rs24
-rw-r--r--src/tools/clippy/tests/ui/bytecount.stderr26
-rw-r--r--src/tools/clippy/tests/ui/cast.rs95
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr142
-rw-r--r--src/tools/clippy/tests/ui/cast_alignment.rs27
-rw-r--r--src/tools/clippy/tests/ui/cast_alignment.stderr16
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.fixed45
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.rs45
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.stderr70
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.fixed47
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.rs47
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.stderr118
-rw-r--r--src/tools/clippy/tests/ui/cast_ref_to_mut.rs31
-rw-r--r--src/tools/clippy/tests/ui/cast_ref_to_mut.stderr22
-rw-r--r--src/tools/clippy/tests/ui/cast_size.rs35
-rw-r--r--src/tools/clippy/tests/ui/cast_size.stderr116
-rw-r--r--src/tools/clippy/tests/ui/cast_size_32bit.rs35
-rw-r--r--src/tools/clippy/tests/ui/cast_size_32bit.stderr132
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed31
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs31
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr16
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.rs5
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.stderr11
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed10
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs10
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr35
-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.stderr52
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stdout0
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs54
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr192
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs15
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr31
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs53
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr131
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy_impl.rs22
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy_mut.rs18
-rw-r--r--src/tools/clippy/tests/ui/cmp_nan.rs34
-rw-r--r--src/tools/clippy/tests/ui/cmp_nan.stderr148
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.rs17
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.stderr16
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed72
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs72
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr40
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs52
-rw-r--r--src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr22
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity.rs395
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity.stderr139
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs15
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr11
-rw-r--r--src/tools/clippy/tests/ui/collapsible_else_if.fixed66
-rw-r--r--src/tools/clippy/tests/ui/collapsible_else_if.rs80
-rw-r--r--src/tools/clippy/tests/ui/collapsible_else_if.stderr154
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.fixed138
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.rs152
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.stderr122
-rw-r--r--src/tools/clippy/tests/ui/collapsible_span_lint_calls.fixed91
-rw-r--r--src/tools/clippy/tests/ui/collapsible_span_lint_calls.rs101
-rw-r--r--src/tools/clippy/tests/ui/collapsible_span_lint_calls.stderr49
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.rs140
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.stderr97
-rw-r--r--src/tools/clippy/tests/ui/complex_types.rs60
-rw-r--r--src/tools/clippy/tests/ui/complex_types.stderr94
-rw-r--r--src/tools/clippy/tests/ui/copy_iterator.rs23
-rw-r--r--src/tools/clippy/tests/ui/copy_iterator.stderr17
-rw-r--r--src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/ice-4727-aux.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs37
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/use_self_macro.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/cc_seme.rs29
-rw-r--r--src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1588.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1782.rs28
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1969.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2499.rs28
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2594.rs22
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2636.rs22
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2636.stderr17
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2727.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2760.rs25
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2774.rs29
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2862.rs18
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2865.rs18
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3151.rs17
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3462.rs25
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-360.rs12
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-360.stderr24
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3717.rs10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3717.stderr22
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3741.rs12
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3747.rs19
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3891.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3891.stderr10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4121.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4545.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4579.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4671.rs21
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4727.rs8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4760.rs10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4775.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4968.rs20
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5207.rs7
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5223.rs18
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5238.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5497.rs11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-700.rs11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs21
-rw-r--r--src/tools/clippy/tests/ui/crashes/if_same_then_else.rs18
-rw-r--r--src/tools/clippy/tests/ui/crashes/inherent_impl.rs26
-rw-r--r--src/tools/clippy/tests/ui/crashes/issue-825.rs27
-rw-r--r--src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs30
-rw-r--r--src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs20
-rw-r--r--src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs36
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs22
-rw-r--r--src/tools/clippy/tests/ui/crashes/procedural_macro.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/regressions.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/returns.rs25
-rw-r--r--src/tools/clippy/tests/ui/crashes/shadow.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/single-match-else.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/trivial_bounds.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs21
-rw-r--r--src/tools/clippy/tests/ui/crashes/whitelist/clippy.toml3
-rw-r--r--src/tools/clippy/tests/ui/crashes/whitelist/conf_whitelisted.rs1
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs12
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr11
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs33
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs6
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr11
-rw-r--r--src/tools/clippy/tests/ui/cstring.rs24
-rw-r--r--src/tools/clippy/tests/ui/cstring.stderr46
-rw-r--r--src/tools/clippy/tests/ui/custom_ice_message.rs10
-rw-r--r--src/tools/clippy/tests/ui/custom_ice_message.stderr11
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro.rs23
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro.stderr80
-rw-r--r--src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs133
-rw-r--r--src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr172
-rw-r--r--src/tools/clippy/tests/ui/decimal_literal_representation.fixed27
-rw-r--r--src/tools/clippy/tests/ui/decimal_literal_representation.rs27
-rw-r--r--src/tools/clippy/tests/ui/decimal_literal_representation.stderr46
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.rs93
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr110
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs29
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.stderr10
-rw-r--r--src/tools/clippy/tests/ui/default_lint.rs27
-rw-r--r--src/tools/clippy/tests/ui/default_lint.stderr21
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.rs103
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr52
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs11
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr64
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.rs7
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.stderr40
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.fixed39
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.rs39
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.stderr52
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs23
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr22
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof_macro.rs10
-rw-r--r--src/tools/clippy/tests/ui/dereference.fixed93
-rw-r--r--src/tools/clippy/tests/ui/dereference.rs93
-rw-r--r--src/tools/clippy/tests/ui/dereference.stderr70
-rw-r--r--src/tools/clippy/tests/ui/derive.rs74
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr83
-rw-r--r--src/tools/clippy/tests/ui/derive_hash_xor_eq.rs54
-rw-r--r--src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr67
-rw-r--r--src/tools/clippy/tests/ui/diverging_sub_expression.rs42
-rw-r--r--src/tools/clippy/tests/ui/diverging_sub_expression.stderr40
-rw-r--r--src/tools/clippy/tests/ui/dlist.rs40
-rw-r--r--src/tools/clippy/tests/ui/dlist.stderr51
-rw-r--r--src/tools/clippy/tests/ui/doc.rs184
-rw-r--r--src/tools/clippy/tests/ui/doc.stderr184
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.rs103
-rw-r--r--src/tools/clippy/tests/ui/doc_errors.stderr58
-rw-r--r--src/tools/clippy/tests/ui/doc_unsafe.rs100
-rw-r--r--src/tools/clippy/tests/ui/doc_unsafe.stderr47
-rw-r--r--src/tools/clippy/tests/ui/double_comparison.fixed30
-rw-r--r--src/tools/clippy/tests/ui/double_comparison.rs30
-rw-r--r--src/tools/clippy/tests/ui/double_comparison.stderr52
-rw-r--r--src/tools/clippy/tests/ui/double_must_use.rs27
-rw-r--r--src/tools/clippy/tests/ui/double_must_use.stderr27
-rw-r--r--src/tools/clippy/tests/ui/double_neg.rs7
-rw-r--r--src/tools/clippy/tests/ui/double_neg.stderr10
-rw-r--r--src/tools/clippy/tests/ui/double_parens.rs56
-rw-r--r--src/tools/clippy/tests/ui/double_parens.stderr40
-rw-r--r--src/tools/clippy/tests/ui/drop_bounds.rs8
-rw-r--r--src/tools/clippy/tests/ui/drop_bounds.stderr16
-rw-r--r--src/tools/clippy/tests/ui/drop_forget_copy.rs66
-rw-r--r--src/tools/clippy/tests/ui/drop_forget_copy.stderr76
-rw-r--r--src/tools/clippy/tests/ui/drop_ref.rs72
-rw-r--r--src/tools/clippy/tests/ui/drop_ref.stderr111
-rw-r--r--src/tools/clippy/tests/ui/duplicate_underscore_argument.rs10
-rw-r--r--src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr10
-rw-r--r--src/tools/clippy/tests/ui/duration_subsec.fixed29
-rw-r--r--src/tools/clippy/tests/ui/duration_subsec.rs29
-rw-r--r--src/tools/clippy/tests/ui/duration_subsec.stderr34
-rw-r--r--src/tools/clippy/tests/ui/else_if_without_else.rs58
-rw-r--r--src/tools/clippy/tests/ui/else_if_without_else.stderr27
-rw-r--r--src/tools/clippy/tests/ui/empty_enum.rs6
-rw-r--r--src/tools/clippy/tests/ui/empty_enum.stderr11
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs96
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr54
-rw-r--r--src/tools/clippy/tests/ui/empty_loop.rs51
-rw-r--r--src/tools/clippy/tests/ui/empty_loop.stderr22
-rw-r--r--src/tools/clippy/tests/ui/entry_fixable.fixed15
-rw-r--r--src/tools/clippy/tests/ui/entry_fixable.rs17
-rw-r--r--src/tools/clippy/tests/ui/entry_fixable.stderr12
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.rs73
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.stderr57
-rw-r--r--src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs50
-rw-r--r--src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr58
-rw-r--r--src/tools/clippy/tests/ui/enum_glob_use.fixed30
-rw-r--r--src/tools/clippy/tests/ui/enum_glob_use.rs30
-rw-r--r--src/tools/clippy/tests/ui/enum_glob_use.stderr22
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs136
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.stderr101
-rw-r--r--src/tools/clippy/tests/ui/eq_op.rs87
-rw-r--r--src/tools/clippy/tests/ui/eq_op.stderr166
-rw-r--r--src/tools/clippy/tests/ui/erasing_op.rs9
-rw-r--r--src/tools/clippy/tests/ui/erasing_op.stderr22
-rw-r--r--src/tools/clippy/tests/ui/escape_analysis.rs176
-rw-r--r--src/tools/clippy/tests/ui/escape_analysis.stderr16
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed204
-rw-r--r--src/tools/clippy/tests/ui/eta.rs204
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr80
-rw-r--r--src/tools/clippy/tests/ui/eval_order_dependence.rs109
-rw-r--r--src/tools/clippy/tests/ui/eval_order_dependence.stderr51
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.fixed63
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.rs63
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr112
-rw-r--r--src/tools/clippy/tests/ui/exit1.rs15
-rw-r--r--src/tools/clippy/tests/ui/exit1.stderr10
-rw-r--r--src/tools/clippy/tests/ui/exit2.rs13
-rw-r--r--src/tools/clippy/tests/ui/exit2.stderr10
-rw-r--r--src/tools/clippy/tests/ui/exit3.rs8
-rw-r--r--src/tools/clippy/tests/ui/expect.rs16
-rw-r--r--src/tools/clippy/tests/ui/expect.stderr20
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.fixed94
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.rs94
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.stderr76
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs147
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.stderr46
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.fixed51
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.rs51
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.stderr52
-rw-r--r--src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs8
-rw-r--r--src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr10
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.rs69
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr28
-rw-r--r--src/tools/clippy/tests/ui/fallible_impl_from.rs76
-rw-r--r--src/tools/clippy/tests/ui/fallible_impl_from.stderr93
-rw-r--r--src/tools/clippy/tests/ui/filetype_is_file.rs23
-rw-r--r--src/tools/clippy/tests/ui/filetype_is_file.stderr27
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next.rs20
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next.stderr24
-rw-r--r--src/tools/clippy/tests/ui/filter_methods.rs24
-rw-r--r--src/tools/clippy/tests/ui/filter_methods.stderr47
-rw-r--r--src/tools/clippy/tests/ui/find_map.rs32
-rw-r--r--src/tools/clippy/tests/ui/find_map.stderr26
-rw-r--r--src/tools/clippy/tests/ui/float_arithmetic.rs52
-rw-r--r--src/tools/clippy/tests/ui/float_arithmetic.stderr106
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs119
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr51
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.rs62
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.stderr67
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.fixed98
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.rs126
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.stderr80
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.fixed18
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.rs18
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.stderr28
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.fixed58
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.rs58
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.stderr174
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.fixed21
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.rs21
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.stderr58
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.fixed42
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.rs42
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.stderr150
-rw-r--r--src/tools/clippy/tests/ui/fn_address_comparisons.rs20
-rw-r--r--src/tools/clippy/tests/ui/fn_address_comparisons.stderr16
-rw-r--r--src/tools/clippy/tests/ui/fn_params_excessive_bools.rs44
-rw-r--r--src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr53
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast.rs55
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr144
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs55
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr144
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.rs50
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.stderr58
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.fixed337
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.rs337
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.stderr152
-rw-r--r--src/tools/clippy/tests/ui/for_loop_over_option_result.rs59
-rw-r--r--src/tools/clippy/tests/ui/for_loop_over_option_result.stderr72
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.rs40
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.stderr9
-rw-r--r--src/tools/clippy/tests/ui/forget_ref.rs48
-rw-r--r--src/tools/clippy/tests/ui/forget_ref.stderr111
-rw-r--r--src/tools/clippy/tests/ui/format.fixed67
-rw-r--r--src/tools/clippy/tests/ui/format.rs70
-rw-r--r--src/tools/clippy/tests/ui/format.stderr85
-rw-r--r--src/tools/clippy/tests/ui/formatting.rs157
-rw-r--r--src/tools/clippy/tests/ui/formatting.stderr127
-rw-r--r--src/tools/clippy/tests/ui/functions.rs104
-rw-r--r--src/tools/clippy/tests/ui/functions.stderr90
-rw-r--r--src/tools/clippy/tests/ui/functions_maxlines.rs163
-rw-r--r--src/tools/clippy/tests/ui/functions_maxlines.stderr16
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.rs79
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.stderr125
-rw-r--r--src/tools/clippy/tests/ui/get_last_with_len.fixed31
-rw-r--r--src/tools/clippy/tests/ui/get_last_with_len.rs31
-rw-r--r--src/tools/clippy/tests/ui/get_last_with_len.stderr10
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.fixed62
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.rs62
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr86
-rw-r--r--src/tools/clippy/tests/ui/identity_conversion.fixed58
-rw-r--r--src/tools/clippy/tests/ui/identity_conversion.rs58
-rw-r--r--src/tools/clippy/tests/ui/identity_conversion.stderr68
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs36
-rw-r--r--src/tools/clippy/tests/ui/identity_op.stderr52
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.rs42
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.stderr29
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.fixed35
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.rs35
-rw-r--r--src/tools/clippy/tests/ui/if_let_some_result.stderr25
-rw-r--r--src/tools/clippy/tests/ui/if_not_else.rs19
-rw-r--r--src/tools/clippy/tests/ui/if_not_else.stderr27
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs145
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr112
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs139
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.stderr125
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs46
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr39
-rw-r--r--src/tools/clippy/tests/ui/impl.rs36
-rw-r--r--src/tools/clippy/tests/ui/impl.stderr35
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.rs99
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.stderr153
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.fixed101
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.rs101
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.stderr70
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.fixed160
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.rs206
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.stderr188
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed43
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs43
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr70
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs31
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr79
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_slice.rs37
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_slice.stderr137
-rw-r--r--src/tools/clippy/tests/ui/inefficient_to_string.fixed31
-rw-r--r--src/tools/clippy/tests/ui/inefficient_to_string.rs31
-rw-r--r--src/tools/clippy/tests/ui/inefficient_to_string.stderr55
-rw-r--r--src/tools/clippy/tests/ui/infallible_destructuring_match.fixed112
-rw-r--r--src/tools/clippy/tests/ui/infallible_destructuring_match.rs118
-rw-r--r--src/tools/clippy/tests/ui/infallible_destructuring_match.stderr28
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.rs69
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.stderr109
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.rs206
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr95
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.rs96
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.stderr28
-rw-r--r--src/tools/clippy/tests/ui/inline_fn_without_body.fixed17
-rw-r--r--src/tools/clippy/tests/ui/inline_fn_without_body.rs20
-rw-r--r--src/tools/clippy/tests/ui/inline_fn_without_body.stderr28
-rw-r--r--src/tools/clippy/tests/ui/int_plus_one.fixed17
-rw-r--r--src/tools/clippy/tests/ui/int_plus_one.rs17
-rw-r--r--src/tools/clippy/tests/ui/int_plus_one.stderr28
-rw-r--r--src/tools/clippy/tests/ui/integer_arithmetic.rs99
-rw-r--r--src/tools/clippy/tests/ui/integer_arithmetic.stderr131
-rw-r--r--src/tools/clippy/tests/ui/integer_division.rs9
-rw-r--r--src/tools/clippy/tests/ui/integer_division.stderr27
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.fixed43
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.rs43
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.stderr160
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs85
-rw-r--r--src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr166
-rw-r--r--src/tools/clippy/tests/ui/issue-3145.rs3
-rw-r--r--src/tools/clippy/tests/ui/issue-3145.stderr8
-rw-r--r--src/tools/clippy/tests/ui/issue-3746.rs22
-rw-r--r--src/tools/clippy/tests/ui/issue_2356.rs24
-rw-r--r--src/tools/clippy/tests/ui/issue_2356.stderr14
-rw-r--r--src/tools/clippy/tests/ui/issue_4266.rs37
-rw-r--r--src/tools/clippy/tests/ui/issue_4266.stderr16
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.rs36
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.stderr20
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.fixed22
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.rs25
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.stderr26
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.rs56
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.stderr59
-rw-r--r--src/tools/clippy/tests/ui/iter_nth_zero.fixed31
-rw-r--r--src/tools/clippy/tests/ui/iter_nth_zero.rs31
-rw-r--r--src/tools/clippy/tests/ui/iter_nth_zero.stderr22
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.rs22
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.stderr35
-rw-r--r--src/tools/clippy/tests/ui/iterator_step_by_zero.rs28
-rw-r--r--src/tools/clippy/tests/ui/iterator_step_by_zero.stderr46
-rw-r--r--src/tools/clippy/tests/ui/large_const_arrays.fixed37
-rw-r--r--src/tools/clippy/tests/ui/large_const_arrays.rs37
-rw-r--r--src/tools/clippy/tests/ui/large_const_arrays.stderr76
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.fixed31
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.rs31
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.stderr42
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.rs54
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.stderr68
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.rs30
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.stderr35
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs145
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.stderr54
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed143
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs143
-rw-r--r--src/tools/clippy/tests/ui/len_zero.stderr88
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs119
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.stderr50
-rw-r--r--src/tools/clippy/tests/ui/let_return.rs70
-rw-r--r--src/tools/clippy/tests/ui/let_return.stderr31
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.rs13
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.stderr51
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_must_use.rs94
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_must_use.stderr99
-rw-r--r--src/tools/clippy/tests/ui/let_unit.fixed63
-rw-r--r--src/tools/clippy/tests/ui/let_unit.rs63
-rw-r--r--src/tools/clippy/tests/ui/let_unit.stderr38
-rw-r--r--src/tools/clippy/tests/ui/lint_without_lint_pass.rs44
-rw-r--r--src/tools/clippy/tests/ui/lint_without_lint_pass.stderr21
-rw-r--r--src/tools/clippy/tests/ui/literals.rs36
-rw-r--r--src/tools/clippy/tests/ui/literals.stderr73
-rw-r--r--src/tools/clippy/tests/ui/logic_bug.rs26
-rw-r--r--src/tools/clippy/tests/ui/logic_bug.stderr63
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.fixed35
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.rs35
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.stderr70
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.rs11
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy.rs110
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy.stderr76
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed45
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs55
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr163
-rw-r--r--src/tools/clippy/tests/ui/many_single_char_names.rs73
-rw-r--r--src/tools/clippy/tests/ui/many_single_char_names.stderr51
-rw-r--r--src/tools/clippy/tests/ui/map_clone.fixed47
-rw-r--r--src/tools/clippy/tests/ui/map_clone.rs47
-rw-r--r--src/tools/clippy/tests/ui/map_clone.stderr40
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.fixed9
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.rs9
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.stderr16
-rw-r--r--src/tools/clippy/tests/ui/map_unit_fn.rs11
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.fixed35
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.rs44
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.stderr33
-rw-r--r--src/tools/clippy/tests/ui/match_bool.rs55
-rw-r--r--src/tools/clippy/tests/ui/match_bool.stderr117
-rw-r--r--src/tools/clippy/tests/ui/match_on_vec_items.rs130
-rw-r--r--src/tools/clippy/tests/ui/match_on_vec_items.stderr52
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.rs82
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.stderr63
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.rs74
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.stderr91
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.rs56
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.stderr139
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs124
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr145
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed90
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs102
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr171
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.rs65
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.stderr35
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.fixed45
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.rs45
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant.stderr94
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs16
-rw-r--r--src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr20
-rw-r--r--src/tools/clippy/tests/ui/mem_forget.rs23
-rw-r--r--src/tools/clippy/tests/ui/mem_forget.stderr22
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.fixed30
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.rs30
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.stderr36
-rw-r--r--src/tools/clippy/tests/ui/mem_replace_macro.rs21
-rw-r--r--src/tools/clippy/tests/ui/mem_replace_macro.stderr14
-rw-r--r--src/tools/clippy/tests/ui/methods.rs247
-rw-r--r--src/tools/clippy/tests/ui/methods.stderr109
-rw-r--r--src/tools/clippy/tests/ui/min_max.rs33
-rw-r--r--src/tools/clippy/tests/ui/min_max.stderr46
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed30
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs30
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr51
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed62
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_unix.rs62
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr183
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-crate-missing.rs3
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr12
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-crate.rs5
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-crate.stderr0
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.rs87
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.stderr103
-rw-r--r--src/tools/clippy/tests/ui/missing-doc.rs102
-rw-r--r--src/tools/clippy/tests/ui/missing-doc.stderr159
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs103
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.stderr0
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs74
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr77
-rw-r--r--src/tools/clippy/tests/ui/missing_inline.rs66
-rw-r--r--src/tools/clippy/tests/ui/missing_inline.stderr40
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed24
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.rs24
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr82
-rw-r--r--src/tools/clippy/tests/ui/module_inception.rs21
-rw-r--r--src/tools/clippy/tests/ui/module_inception.stderr20
-rw-r--r--src/tools/clippy/tests/ui/module_name_repetitions.rs26
-rw-r--r--src/tools/clippy/tests/ui/module_name_repetitions.stderr34
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_float.rs36
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr83
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs90
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr156
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs44
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr156
-rw-r--r--src/tools/clippy/tests/ui/modulo_one.rs14
-rw-r--r--src/tools/clippy/tests/ui/modulo_one.stderr30
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed93
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs93
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.stderr34
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.fixed26
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.rs26
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.stderr28
-rw-r--r--src/tools/clippy/tests/ui/mut_from_ref.rs46
-rw-r--r--src/tools/clippy/tests/ui/mut_from_ref.stderr63
-rw-r--r--src/tools/clippy/tests/ui/mut_key.rs55
-rw-r--r--src/tools/clippy/tests/ui/mut_key.stderr28
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.rs49
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.stderr63
-rw-r--r--src/tools/clippy/tests/ui/mut_range_bound.rs63
-rw-r--r--src/tools/clippy/tests/ui/mut_range_bound.stderr34
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.rs43
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr22
-rw-r--r--src/tools/clippy/tests/ui/mutex_atomic.rs15
-rw-r--r--src/tools/clippy/tests/ui/mutex_atomic.stderr48
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.fixed98
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.rs130
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.stderr111
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/simple.rs46
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/simple.stderr44
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed61
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs61
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr28
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.fixed45
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.rs45
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.fixed21
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.rs21
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.stderr28
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.rs115
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.stderr99
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.rs74
-rw-r--r--src/tools/clippy/tests/ui/needless_doc_main.stderr22
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs262
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr106
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.rs161
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.stderr178
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs21
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.rs95
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr157
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop2.rs85
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop2.stderr91
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed78
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs78
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr76
-rw-r--r--src/tools/clippy/tests/ui/needless_update.rs14
-rw-r--r--src/tools/clippy/tests/ui/needless_update.stderr10
-rw-r--r--src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs61
-rw-r--r--src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr28
-rw-r--r--src/tools/clippy/tests/ui/neg_multiply.rs35
-rw-r--r--src/tools/clippy/tests/ui/neg_multiply.stderr16
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs204
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr100
-rw-r--r--src/tools/clippy/tests/ui/new_ret_no_self.rs212
-rw-r--r--src/tools/clippy/tests/ui/new_ret_no_self.stderr52
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.rs151
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.stderr46
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs102
-rw-r--r--src/tools/clippy/tests/ui/no_effect.stderr154
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names.rs56
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names.stderr40
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names.stdout0
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs52
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr111
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods.rs110
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr82
-rw-r--r--src/tools/clippy/tests/ui/ok_expect.rs27
-rw-r--r--src/tools/clippy/tests/ui/ok_expect.stderr43
-rw-r--r--src/tools/clippy/tests/ui/op_ref.rs58
-rw-r--r--src/tools/clippy/tests/ui/op_ref.stderr22
-rw-r--r--src/tools/clippy/tests/ui/open_options.rs14
-rw-r--r--src/tools/clippy/tests/ui/open_options.stderr46
-rw-r--r--src/tools/clippy/tests/ui/option_and_then_some.fixed25
-rw-r--r--src/tools/clippy/tests/ui/option_and_then_some.rs25
-rw-r--r--src/tools/clippy/tests/ui/option_and_then_some.stderr20
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.fixed41
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.rs44
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.stderr104
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.rs23
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr61
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.fixed16
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.rs16
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.stderr26
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed84
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs84
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr148
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs39
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr27
-rw-r--r--src/tools/clippy/tests/ui/option_map_unwrap_or.rs88
-rw-r--r--src/tools/clippy/tests/ui/option_map_unwrap_or.stderr138
-rw-r--r--src/tools/clippy/tests/ui/option_option.rs62
-rw-r--r--src/tools/clippy/tests/ui/option_option.stderr62
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed110
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs110
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr82
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs11
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr16
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs22
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr40
-rw-r--r--src/tools/clippy/tests/ui/outer_expn_data.fixed28
-rw-r--r--src/tools/clippy/tests/ui/outer_expn_data.rs28
-rw-r--r--src/tools/clippy/tests/ui/outer_expn_data.stderr15
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.rs26
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.stderr52
-rw-r--r--src/tools/clippy/tests/ui/panic.rs61
-rw-r--r--src/tools/clippy/tests/ui/panic.stderr28
-rw-r--r--src/tools/clippy/tests/ui/panicking_macros.rs33
-rw-r--r--src/tools/clippy/tests/ui/panicking_macros.stderr34
-rw-r--r--src/tools/clippy/tests/ui/partialeq_ne_impl.rs26
-rw-r--r--src/tools/clippy/tests/ui/partialeq_ne_impl.stderr12
-rw-r--r--src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed8
-rw-r--r--src/tools/clippy/tests/ui/path_buf_push_overwrite.rs8
-rw-r--r--src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr10
-rw-r--r--src/tools/clippy/tests/ui/patterns.fixed36
-rw-r--r--src/tools/clippy/tests/ui/patterns.rs36
-rw-r--r--src/tools/clippy/tests/ui/patterns.stderr22
-rw-r--r--src/tools/clippy/tests/ui/precedence.fixed53
-rw-r--r--src/tools/clippy/tests/ui/precedence.rs53
-rw-r--r--src/tools/clippy/tests/ui/precedence.stderr58
-rw-r--r--src/tools/clippy/tests/ui/print.rs35
-rw-r--r--src/tools/clippy/tests/ui/print.stderr54
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs38
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr88
-rw-r--r--src/tools/clippy/tests/ui/print_with_newline.rs51
-rw-r--r--src/tools/clippy/tests/ui/print_with_newline.stderr110
-rw-r--r--src/tools/clippy/tests/ui/println_empty_string.fixed11
-rw-r--r--src/tools/clippy/tests/ui/println_empty_string.rs11
-rw-r--r--src/tools/clippy/tests/ui/println_empty_string.stderr16
-rw-r--r--src/tools/clippy/tests/ui/proc_macro.rs26
-rw-r--r--src/tools/clippy/tests/ui/proc_macro.stderr10
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs86
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr89
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed20
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.rs20
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr16
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed125
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs155
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr104
-rw-r--r--src/tools/clippy/tests/ui/range.rs16
-rw-r--r--src/tools/clippy/tests/ui/range.stderr10
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.fixed41
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.rs41
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.stderr60
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.fixed48
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.rs48
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.stderr52
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed172
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs172
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr171
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call.rs23
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call.stderr28
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed8
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs8
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.fixed71
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.rs71
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.stderr46
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching.fixed119
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching.rs140
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching.stderr194
-rw-r--r--src/tools/clippy/tests/ui/redundant_pub_crate.fixed107
-rw-r--r--src/tools/clippy/tests/ui/redundant_pub_crate.rs107
-rw-r--r--src/tools/clippy/tests/ui/redundant_pub_crate.stderr132
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed56
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.rs56
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr100
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs13
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr64
-rw-r--r--src/tools/clippy/tests/ui/regex.rs79
-rw-r--r--src/tools/clippy/tests/ui/regex.stderr171
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed19
-rw-r--r--src/tools/clippy/tests/ui/rename.rs19
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr34
-rw-r--r--src/tools/clippy/tests/ui/renamed_builtin_attr.fixed4
-rw-r--r--src/tools/clippy/tests/ui/renamed_builtin_attr.rs4
-rw-r--r--src/tools/clippy/tests/ui/renamed_builtin_attr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/repl_uninit.rs35
-rw-r--r--src/tools/clippy/tests/ui/repl_uninit.stderr27
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs42
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr27
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.fixed19
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.rs19
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.stderr10
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed80
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs80
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr140
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs46
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr58
-rw-r--r--src/tools/clippy/tests/ui/result_map_unwrap_or_else.rs23
-rw-r--r--src/tools/clippy/tests/ui/result_map_unwrap_or_else.stderr27
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.rs80
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr75
-rw-r--r--src/tools/clippy/tests/ui/serde.rs47
-rw-r--r--src/tools/clippy/tests/ui/serde.stderr15
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs53
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr138
-rw-r--r--src/tools/clippy/tests/ui/short_circuit_statement.fixed18
-rw-r--r--src/tools/clippy/tests/ui/short_circuit_statement.rs18
-rw-r--r--src/tools/clippy/tests/ui/short_circuit_statement.stderr22
-rw-r--r--src/tools/clippy/tests/ui/similar_names.rs103
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr107
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed63
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs63
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr166
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.fixed21
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.rs21
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.stderr10
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs95
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr69
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs35
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr23
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.rs29
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.stderr23
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs63
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr60
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.fixed46
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.rs46
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.stderr78
-rw-r--r--src/tools/clippy/tests/ui/string_add.rs26
-rw-r--r--src/tools/clippy/tests/ui/string_add.stderr30
-rw-r--r--src/tools/clippy/tests/ui/string_add_assign.fixed21
-rw-r--r--src/tools/clippy/tests/ui/string_add_assign.rs21
-rw-r--r--src/tools/clippy/tests/ui/string_add_assign.stderr24
-rw-r--r--src/tools/clippy/tests/ui/string_extend.fixed32
-rw-r--r--src/tools/clippy/tests/ui/string_extend.rs32
-rw-r--r--src/tools/clippy/tests/ui/string_extend.stderr22
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.fixed22
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.rs22
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.stderr28
-rw-r--r--src/tools/clippy/tests/ui/struct_excessive_bools.rs44
-rw-r--r--src/tools/clippy/tests/ui/struct_excessive_bools.stderr29
-rw-r--r--src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs90
-rw-r--r--src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr24
-rw-r--r--src/tools/clippy/tests/ui/suspicious_map.rs5
-rw-r--r--src/tools/clippy/tests/ui/suspicious_map.stderr11
-rw-r--r--src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs23
-rw-r--r--src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr35
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed83
-rw-r--r--src/tools/clippy/tests/ui/swap.rs95
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr69
-rw-r--r--src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed22
-rw-r--r--src/tools/clippy/tests/ui/tabs_in_doc_comments.rs22
-rw-r--r--src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr52
-rw-r--r--src/tools/clippy/tests/ui/temporary_assignment.rs75
-rw-r--r--src/tools/clippy/tests/ui/temporary_assignment.stderr56
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.fixed11
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.rs11
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.stderr16
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.fixed29
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.rs29
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.stderr34
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs11
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr10
-rw-r--r--src/tools/clippy/tests/ui/trailing_zeros.rs9
-rw-r--r--src/tools/clippy/tests/ui/trailing_zeros.stderr16
-rw-r--r--src/tools/clippy/tests/ui/transmute.rs94
-rw-r--r--src/tools/clippy/tests/ui/transmute.stderr146
-rw-r--r--src/tools/clippy/tests/ui/transmute_32bit.rs14
-rw-r--r--src/tools/clippy/tests/ui/transmute_32bit.stderr28
-rw-r--r--src/tools/clippy/tests/ui/transmute_64bit.rs10
-rw-r--r--src/tools/clippy/tests/ui/transmute_64bit.stderr16
-rw-r--r--src/tools/clippy/tests/ui/transmute_collection.rs47
-rw-r--r--src/tools/clippy/tests/ui/transmute_collection.stderr112
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.rs12
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.stderr40
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs54
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr40
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs41
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr64
-rw-r--r--src/tools/clippy/tests/ui/transmuting_null.rs30
-rw-r--r--src/tools/clippy/tests/ui/transmuting_null.stderr22
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs114
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr98
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed106
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs106
-rw-r--r--src/tools/clippy/tests/ui/try_err.stderr38
-rw-r--r--src/tools/clippy/tests/ui/ty_fn_sig.rs14
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.rs19
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr15
-rw-r--r--src/tools/clippy/tests/ui/types.fixed15
-rw-r--r--src/tools/clippy/tests/ui/types.rs15
-rw-r--r--src/tools/clippy/tests/ui/types.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unicode.rs23
-rw-r--r--src/tools/clippy/tests/ui/unicode.stderr26
-rw-r--r--src/tools/clippy/tests/ui/uninit.rs22
-rw-r--r--src/tools/clippy/tests/ui/uninit.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.fixed64
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.rs71
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.stderr79
-rw-r--r--src/tools/clippy/tests/ui/unit_cmp.rs57
-rw-r--r--src/tools/clippy/tests/ui/unit_cmp.stderr82
-rw-r--r--src/tools/clippy/tests/ui/unknown_attribute.rs3
-rw-r--r--src/tools/clippy/tests/ui/unknown_attribute.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unknown_clippy_lints.fixed18
-rw-r--r--src/tools/clippy/tests/ui/unknown_clippy_lints.rs18
-rw-r--r--src/tools/clippy/tests/ui/unknown_clippy_lints.stderr52
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast_fixable.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.rs117
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.stderr130
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.rs17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.stderr38
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_flat_map.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_flat_map.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_flat_map.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.fixed52
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.rs52
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fold.stderr40
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.fixed79
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.rs83
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.stderr128
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.rs22
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.stderr19
-rw-r--r--src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed45
-rw-r--r--src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs45
-rw-r--r--src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr92
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.fixed35
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.rs35
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.stderr58
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs60
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr39
-rw-r--r--src/tools/clippy/tests/ui/unsafe_removed_from_name.rs27
-rw-r--r--src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed41
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.rs41
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr63
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs25
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.stderr40
-rw-r--r--src/tools/clippy/tests/ui/unused_self.rs140
-rw-r--r--src/tools/clippy/tests/ui/unused_self.stderr75
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.fixed59
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs60
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.stderr52
-rw-r--r--src/tools/clippy/tests/ui/unwrap.rs16
-rw-r--r--src/tools/clippy/tests/ui/unwrap.stderr20
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or.rs9
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or.stderr16
-rwxr-xr-xsrc/tools/clippy/tests/ui/update-all-references.sh21
-rwxr-xr-xsrc/tools/clippy/tests/ui/update-references.sh44
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed253
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs253
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr164
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.fixed114
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.rs114
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.stderr94
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.rs119
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.stderr40
-rw-r--r--src/tools/clippy/tests/ui/useful_asref.rs13
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed135
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs135
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.stderr74
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed61
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs61
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.stderr22
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed55
-rw-r--r--src/tools/clippy/tests/ui/vec.rs55
-rw-r--r--src/tools/clippy/tests/ui/vec.stderr40
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.fixed38
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.rs38
-rw-r--r--src/tools/clippy/tests/ui/vec_box_sized.stderr22
-rw-r--r--src/tools/clippy/tests/ui/verbose_file_reads.rs28
-rw-r--r--src/tools/clippy/tests/ui/verbose_file_reads.stderr19
-rw-r--r--src/tools/clippy/tests/ui/vtable_address_comparisons.rs42
-rw-r--r--src/tools/clippy/tests/ui/vtable_address_comparisons.stderr83
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.rs119
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.stderr63
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed160
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs160
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr28
-rw-r--r--src/tools/clippy/tests/ui/wild_in_or_pats.rs36
-rw-r--r--src/tools/clippy/tests/ui/wild_in_or_pats.stderr35
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed101
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs101
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr38
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed157
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs158
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr96
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs43
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr88
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.rs58
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.stderr114
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.fixed20
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.rs20
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.stderr16
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.rs77
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.stderr76
-rw-r--r--src/tools/clippy/tests/ui/zero_div_zero.rs13
-rw-r--r--src/tools/clippy/tests/ui/zero_div_zero.stderr61
-rw-r--r--src/tools/clippy/tests/ui/zero_offset.rs12
-rw-r--r--src/tools/clippy/tests/ui/zero_offset.stderr9
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr.fixed14
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr.rs14
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr.stderr34
991 files changed, 55470 insertions, 0 deletions
diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs
new file mode 100644
index 00000000000..d205b383d1f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs
@@ -0,0 +1,61 @@
+#![warn(clippy::absurd_extreme_comparisons)]
+#![allow(
+    unused,
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::needless_pass_by_value
+)]
+
+#[rustfmt::skip]
+fn main() {
+    const Z: u32 = 0;
+    let u: u32 = 42;
+    u <= 0;
+    u <= Z;
+    u < Z;
+    Z >= u;
+    Z > u;
+    u > u32::MAX;
+    u >= u32::MAX;
+    u32::MAX < u;
+    u32::MAX <= u;
+    1-1 > u;
+    u >= !0;
+    u <= 12 - 2*6;
+    let i: i8 = 0;
+    i < -127 - 1;
+    i8::MAX >= i;
+    3-7 < i32::MIN;
+    let b = false;
+    b >= true;
+    false > b;
+    u > 0; // ok
+    // this is handled by clippy::unit_cmp
+    () < {};
+}
+
+use std::cmp::{Ordering, PartialEq, PartialOrd};
+
+#[derive(PartialEq, PartialOrd)]
+pub struct U(u64);
+
+impl PartialEq<u32> for U {
+    fn eq(&self, other: &u32) -> bool {
+        self.eq(&U(u64::from(*other)))
+    }
+}
+impl PartialOrd<u32> for U {
+    fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
+        self.partial_cmp(&U(u64::from(*other)))
+    }
+}
+
+pub fn foo(val: U) -> bool {
+    val > u32::MAX
+}
+
+pub fn bar(len: u64) -> bool {
+    // This is OK as we are casting from target sized to fixed size
+    len >= usize::MAX as u64
+}
diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr
new file mode 100644
index 00000000000..6de554378aa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr
@@ -0,0 +1,147 @@
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:14:5
+   |
+LL |     u <= 0;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings`
+   = help: because `0` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 0` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:15:5
+   |
+LL |     u <= Z;
+   |     ^^^^^^
+   |
+   = help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == Z` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:16:5
+   |
+LL |     u < Z;
+   |     ^^^^^
+   |
+   = help: because `Z` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:17:5
+   |
+LL |     Z >= u;
+   |     ^^^^^^
+   |
+   = help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `Z == u` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:18:5
+   |
+LL |     Z > u;
+   |     ^^^^^
+   |
+   = help: because `Z` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:19:5
+   |
+LL |     u > u32::MAX;
+   |     ^^^^^^^^^^^^
+   |
+   = help: because `u32::MAX` is the maximum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:20:5
+   |
+LL |     u >= u32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == u32::MAX` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:21:5
+   |
+LL |     u32::MAX < u;
+   |     ^^^^^^^^^^^^
+   |
+   = help: because `u32::MAX` is the maximum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:22:5
+   |
+LL |     u32::MAX <= u;
+   |     ^^^^^^^^^^^^^
+   |
+   = help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u32::MAX == u` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:23:5
+   |
+LL |     1-1 > u;
+   |     ^^^^^^^
+   |
+   = help: because `1-1` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:24:5
+   |
+LL |     u >= !0;
+   |     ^^^^^^^
+   |
+   = help: because `!0` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == !0` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:25:5
+   |
+LL |     u <= 12 - 2*6;
+   |     ^^^^^^^^^^^^^
+   |
+   = help: because `12 - 2*6` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 12 - 2*6` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:27:5
+   |
+LL |     i < -127 - 1;
+   |     ^^^^^^^^^^^^
+   |
+   = help: because `-127 - 1` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:28:5
+   |
+LL |     i8::MAX >= i;
+   |     ^^^^^^^^^^^^
+   |
+   = help: because `i8::MAX` is the maximum value for this type, this comparison is always true
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:29:5
+   |
+LL |     3-7 < i32::MIN;
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: because `i32::MIN` is the minimum value for this type, this comparison is always false
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:31:5
+   |
+LL |     b >= true;
+   |     ^^^^^^^^^
+   |
+   = help: because `true` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `b == true` instead
+
+error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
+  --> $DIR/absurd-extreme-comparisons.rs:32:5
+   |
+LL |     false > b;
+   |     ^^^^^^^^^
+   |
+   = help: because `false` is the minimum value for this type, this comparison is always false
+
+error: <-comparison of unit values detected. This will always be false
+  --> $DIR/absurd-extreme-comparisons.rs:35:5
+   |
+LL |     () < {};
+   |     ^^^^^^^
+   |
+   = note: `#[deny(clippy::unit_cmp)]` on by default
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/approx_const.rs b/src/tools/clippy/tests/ui/approx_const.rs
new file mode 100644
index 00000000000..fb57a0becbb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/approx_const.rs
@@ -0,0 +1,60 @@
+#[warn(clippy::approx_constant)]
+#[allow(unused, clippy::shadow_unrelated, clippy::similar_names)]
+fn main() {
+    let my_e = 2.7182;
+    let almost_e = 2.718;
+    let no_e = 2.71;
+
+    let my_1_frac_pi = 0.3183;
+    let no_1_frac_pi = 0.31;
+
+    let my_frac_1_sqrt_2 = 0.70710678;
+    let almost_frac_1_sqrt_2 = 0.70711;
+    let my_frac_1_sqrt_2 = 0.707;
+
+    let my_frac_2_pi = 0.63661977;
+    let no_frac_2_pi = 0.636;
+
+    let my_frac_2_sq_pi = 1.128379;
+    let no_frac_2_sq_pi = 1.128;
+
+    let my_frac_pi_2 = 1.57079632679;
+    let no_frac_pi_2 = 1.5705;
+
+    let my_frac_pi_3 = 1.04719755119;
+    let no_frac_pi_3 = 1.047;
+
+    let my_frac_pi_4 = 0.785398163397;
+    let no_frac_pi_4 = 0.785;
+
+    let my_frac_pi_6 = 0.523598775598;
+    let no_frac_pi_6 = 0.523;
+
+    let my_frac_pi_8 = 0.3926990816987;
+    let no_frac_pi_8 = 0.392;
+
+    let my_ln_10 = 2.302585092994046;
+    let no_ln_10 = 2.303;
+
+    let my_ln_2 = 0.6931471805599453;
+    let no_ln_2 = 0.693;
+
+    let my_log10_e = 0.4342944819032518;
+    let no_log10_e = 0.434;
+
+    let my_log2_e = 1.4426950408889634;
+    let no_log2_e = 1.442;
+
+    let log2_10 = 3.321928094887362;
+    let no_log2_10 = 3.321;
+
+    let log10_2 = 0.301029995663981;
+    let no_log10_2 = 0.301;
+
+    let my_pi = 3.1415;
+    let almost_pi = 3.14;
+    let no_pi = 3.15;
+
+    let my_sq2 = 1.4142;
+    let no_sq2 = 1.414;
+}
diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr
new file mode 100644
index 00000000000..98b85443f0b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/approx_const.stderr
@@ -0,0 +1,130 @@
+error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly
+  --> $DIR/approx_const.rs:4:16
+   |
+LL |     let my_e = 2.7182;
+   |                ^^^^^^
+   |
+   = note: `-D clippy::approx-constant` implied by `-D warnings`
+
+error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly
+  --> $DIR/approx_const.rs:5:20
+   |
+LL |     let almost_e = 2.718;
+   |                    ^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found. Consider using it directly
+  --> $DIR/approx_const.rs:8:24
+   |
+LL |     let my_1_frac_pi = 0.3183;
+   |                        ^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:11:28
+   |
+LL |     let my_frac_1_sqrt_2 = 0.70710678;
+   |                            ^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:12:32
+   |
+LL |     let almost_frac_1_sqrt_2 = 0.70711;
+   |                                ^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found. Consider using it directly
+  --> $DIR/approx_const.rs:15:24
+   |
+LL |     let my_frac_2_pi = 0.63661977;
+   |                        ^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found. Consider using it directly
+  --> $DIR/approx_const.rs:18:27
+   |
+LL |     let my_frac_2_sq_pi = 1.128379;
+   |                           ^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:21:24
+   |
+LL |     let my_frac_pi_2 = 1.57079632679;
+   |                        ^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found. Consider using it directly
+  --> $DIR/approx_const.rs:24:24
+   |
+LL |     let my_frac_pi_3 = 1.04719755119;
+   |                        ^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found. Consider using it directly
+  --> $DIR/approx_const.rs:27:24
+   |
+LL |     let my_frac_pi_4 = 0.785398163397;
+   |                        ^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found. Consider using it directly
+  --> $DIR/approx_const.rs:30:24
+   |
+LL |     let my_frac_pi_6 = 0.523598775598;
+   |                        ^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found. Consider using it directly
+  --> $DIR/approx_const.rs:33:24
+   |
+LL |     let my_frac_pi_8 = 0.3926990816987;
+   |                        ^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LN_10` found. Consider using it directly
+  --> $DIR/approx_const.rs:36:20
+   |
+LL |     let my_ln_10 = 2.302585092994046;
+   |                    ^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LN_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:39:19
+   |
+LL |     let my_ln_2 = 0.6931471805599453;
+   |                   ^^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LOG10_E` found. Consider using it directly
+  --> $DIR/approx_const.rs:42:22
+   |
+LL |     let my_log10_e = 0.4342944819032518;
+   |                      ^^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LOG2_E` found. Consider using it directly
+  --> $DIR/approx_const.rs:45:21
+   |
+LL |     let my_log2_e = 1.4426950408889634;
+   |                     ^^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LOG2_10` found. Consider using it directly
+  --> $DIR/approx_const.rs:48:19
+   |
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::LOG10_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:51:19
+   |
+LL |     let log10_2 = 0.301029995663981;
+   |                   ^^^^^^^^^^^^^^^^^
+
+error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
+  --> $DIR/approx_const.rs:54:17
+   |
+LL |     let my_pi = 3.1415;
+   |                 ^^^^^^
+
+error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
+  --> $DIR/approx_const.rs:55:21
+   |
+LL |     let almost_pi = 3.14;
+   |                     ^^^^
+
+error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it directly
+  --> $DIR/approx_const.rs:58:18
+   |
+LL |     let my_sq2 = 1.4142;
+   |                  ^^^^^^
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs
new file mode 100644
index 00000000000..e01ba0c64df
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_conversions.rs
@@ -0,0 +1,7 @@
+#[warn(clippy::as_conversions)]
+
+fn main() {
+    let i = 0u32 as u64;
+
+    let j = &i as *const u64 as *mut u64;
+}
diff --git a/src/tools/clippy/tests/ui/as_conversions.stderr b/src/tools/clippy/tests/ui/as_conversions.stderr
new file mode 100644
index 00000000000..312d3a7460e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_conversions.stderr
@@ -0,0 +1,27 @@
+error: using a potentially dangerous silent `as` conversion
+  --> $DIR/as_conversions.rs:4:13
+   |
+LL |     let i = 0u32 as u64;
+   |             ^^^^^^^^^^^
+   |
+   = note: `-D clippy::as-conversions` implied by `-D warnings`
+   = help: consider using a safe wrapper for this conversion
+
+error: using a potentially dangerous silent `as` conversion
+  --> $DIR/as_conversions.rs:6:13
+   |
+LL |     let j = &i as *const u64 as *mut u64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a safe wrapper for this conversion
+
+error: using a potentially dangerous silent `as` conversion
+  --> $DIR/as_conversions.rs:6:13
+   |
+LL |     let j = &i as *const u64 as *mut u64;
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a safe wrapper for this conversion
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs
new file mode 100644
index 00000000000..60d721c2f20
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs
@@ -0,0 +1,29 @@
+macro_rules! assert_const {
+    ($len:expr) => {
+        assert!($len > 0);
+        debug_assert!($len < 0);
+    };
+}
+
+fn main() {
+    assert!(true);
+    assert!(false);
+    assert!(true, "true message");
+    assert!(false, "false message");
+
+    let msg = "panic message";
+    assert!(false, msg.to_uppercase());
+
+    const B: bool = true;
+    assert!(B);
+
+    const C: bool = false;
+    assert!(C);
+    assert!(C, "C message");
+
+    debug_assert!(true);
+    // Don't lint this, since there is no better way for expressing "Only panic in debug mode".
+    debug_assert!(false); // #3948
+    assert_const!(3);
+    assert_const!(-1);
+}
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
new file mode 100644
index 00000000000..8f09c8ce9d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
@@ -0,0 +1,84 @@
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:9:5
+   |
+LL |     assert!(true);
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
+   = help: remove it
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(false)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:10:5
+   |
+LL |     assert!(false);
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!()` or `unreachable!()`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:11:5
+   |
+LL |     assert!(true, "true message");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(false, "false message")` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:12:5
+   |
+LL |     assert!(false, "false message");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!("false message")` or `unreachable!("false message")`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(false, msg.to_uppercase())` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:15:5
+   |
+LL |     assert!(false, msg.to_uppercase());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:18:5
+   |
+LL |     assert!(B);
+   |     ^^^^^^^^^^^
+   |
+   = help: remove it
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(false)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:21:5
+   |
+LL |     assert!(C);
+   |     ^^^^^^^^^^^
+   |
+   = help: use `panic!()` or `unreachable!()`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert!(false, "C message")` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:22:5
+   |
+LL |     assert!(C, "C message");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!("C message")` or `unreachable!("C message")`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `debug_assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:24:5
+   |
+LL |     debug_assert!(true);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
new file mode 100644
index 00000000000..52b1b3afe16
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#[allow(dead_code, unused_assignments)]
+#[warn(clippy::assign_op_pattern)]
+fn main() {
+    let mut a = 5;
+    a += 1;
+    a += 1;
+    a -= 1;
+    a *= 99;
+    a *= 42;
+    a /= 2;
+    a %= 5;
+    a &= 1;
+    a = 1 - a;
+    a = 5 / a;
+    a = 42 % a;
+    a = 6 << a;
+    let mut s = String::new();
+    s += "bla";
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
new file mode 100644
index 00000000000..527a46b2c2b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#[allow(dead_code, unused_assignments)]
+#[warn(clippy::assign_op_pattern)]
+fn main() {
+    let mut a = 5;
+    a = a + 1;
+    a = 1 + a;
+    a = a - 1;
+    a = a * 99;
+    a = 42 * a;
+    a = a / 2;
+    a = a % 5;
+    a = a & 1;
+    a = 1 - a;
+    a = 5 / a;
+    a = 42 % a;
+    a = 6 << a;
+    let mut s = String::new();
+    s = s + "bla";
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr
new file mode 100644
index 00000000000..3486bd8da4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assign_ops.stderr
@@ -0,0 +1,58 @@
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:7:5
+   |
+LL |     a = a + 1;
+   |     ^^^^^^^^^ help: replace it with: `a += 1`
+   |
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:8:5
+   |
+LL |     a = 1 + a;
+   |     ^^^^^^^^^ help: replace it with: `a += 1`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:9:5
+   |
+LL |     a = a - 1;
+   |     ^^^^^^^^^ help: replace it with: `a -= 1`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:10:5
+   |
+LL |     a = a * 99;
+   |     ^^^^^^^^^^ help: replace it with: `a *= 99`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:11:5
+   |
+LL |     a = 42 * a;
+   |     ^^^^^^^^^^ help: replace it with: `a *= 42`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:12:5
+   |
+LL |     a = a / 2;
+   |     ^^^^^^^^^ help: replace it with: `a /= 2`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:13:5
+   |
+LL |     a = a % 5;
+   |     ^^^^^^^^^ help: replace it with: `a %= 5`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:14:5
+   |
+LL |     a = a & 1;
+   |     ^^^^^^^^^ help: replace it with: `a &= 1`
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops.rs:20:5
+   |
+LL |     s = s + "bla";
+   |     ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs
new file mode 100644
index 00000000000..4703a8c7777
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assign_ops2.rs
@@ -0,0 +1,55 @@
+#[allow(unused_assignments)]
+#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+fn main() {
+    let mut a = 5;
+    a += a + 1;
+    a += 1 + a;
+    a -= a - 1;
+    a *= a * 99;
+    a *= 42 * a;
+    a /= a / 2;
+    a %= a % 5;
+    a &= a & 1;
+    a *= a * a;
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
+
+// check that we don't lint on op assign impls, because that's just the way to impl them
+
+use std::ops::{Mul, MulAssign};
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct Wrap(i64);
+
+impl Mul<i64> for Wrap {
+    type Output = Self;
+
+    fn mul(self, rhs: i64) -> Self {
+        Wrap(self.0 * rhs)
+    }
+}
+
+impl MulAssign<i64> for Wrap {
+    fn mul_assign(&mut self, rhs: i64) {
+        *self = *self * rhs
+    }
+}
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf = buf + cows.clone();
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+    println!("{}", buf);
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/assign_ops2.stderr
new file mode 100644
index 00000000000..70b15d18a56
--- /dev/null
+++ b/src/tools/clippy/tests/ui/assign_ops2.stderr
@@ -0,0 +1,146 @@
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:5:5
+   |
+LL |     a += a + 1;
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings`
+help: Did you mean `a = a + 1` or `a = a + a + 1`? Consider replacing it with
+   |
+LL |     a += 1;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a + a + 1;
+   |     ^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:6:5
+   |
+LL |     a += 1 + a;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a + 1` or `a = a + 1 + a`? Consider replacing it with
+   |
+LL |     a += 1;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a + 1 + a;
+   |     ^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:7:5
+   |
+LL |     a -= a - 1;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a - 1` or `a = a - (a - 1)`? Consider replacing it with
+   |
+LL |     a -= 1;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a - (a - 1);
+   |     ^^^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:8:5
+   |
+LL |     a *= a * 99;
+   |     ^^^^^^^^^^^
+   |
+help: Did you mean `a = a * 99` or `a = a * a * 99`? Consider replacing it with
+   |
+LL |     a *= 99;
+   |     ^^^^^^^
+help: or
+   |
+LL |     a = a * a * 99;
+   |     ^^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:9:5
+   |
+LL |     a *= 42 * a;
+   |     ^^^^^^^^^^^
+   |
+help: Did you mean `a = a * 42` or `a = a * 42 * a`? Consider replacing it with
+   |
+LL |     a *= 42;
+   |     ^^^^^^^
+help: or
+   |
+LL |     a = a * 42 * a;
+   |     ^^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:10:5
+   |
+LL |     a /= a / 2;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a / 2` or `a = a / (a / 2)`? Consider replacing it with
+   |
+LL |     a /= 2;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a / (a / 2);
+   |     ^^^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:11:5
+   |
+LL |     a %= a % 5;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a % 5` or `a = a % (a % 5)`? Consider replacing it with
+   |
+LL |     a %= 5;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a % (a % 5);
+   |     ^^^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:12:5
+   |
+LL |     a &= a & 1;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a & 1` or `a = a & a & 1`? Consider replacing it with
+   |
+LL |     a &= 1;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a & a & 1;
+   |     ^^^^^^^^^^^^^
+
+error: variable appears on both sides of an assignment operation
+  --> $DIR/assign_ops2.rs:13:5
+   |
+LL |     a *= a * a;
+   |     ^^^^^^^^^^
+   |
+help: Did you mean `a = a * a` or `a = a * a * a`? Consider replacing it with
+   |
+LL |     a *= a;
+   |     ^^^^^^
+help: or
+   |
+LL |     a = a * a * a;
+   |     ^^^^^^^^^^^^^
+
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops2.rs:50:5
+   |
+LL |     buf = buf + cows.clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
+   |
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_bool.rs b/src/tools/clippy/tests/ui/atomic_ordering_bool.rs
new file mode 100644
index 00000000000..cdbde79b19e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_bool.rs
@@ -0,0 +1,25 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicBool, Ordering};
+
+fn main() {
+    let x = AtomicBool::new(true);
+
+    // Allowed load ordering modes
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+
+    // Disallowed load ordering modes
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    // Allowed store ordering modes
+    x.store(false, Ordering::Release);
+    x.store(false, Ordering::SeqCst);
+    x.store(false, Ordering::Relaxed);
+
+    // Disallowed store ordering modes
+    x.store(false, Ordering::Acquire);
+    x.store(false, Ordering::AcqRel);
+}
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_bool.stderr b/src/tools/clippy/tests/ui/atomic_ordering_bool.stderr
new file mode 100644
index 00000000000..397b893aed9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_bool.stderr
@@ -0,0 +1,35 @@
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_bool.rs:14:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_bool.rs:15:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_bool.rs:23:20
+   |
+LL |     x.store(false, Ordering::Acquire);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_bool.rs:24:20
+   |
+LL |     x.store(false, Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_fence.rs b/src/tools/clippy/tests/ui/atomic_ordering_fence.rs
new file mode 100644
index 00000000000..5ee5182ca05
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_fence.rs
@@ -0,0 +1,20 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{compiler_fence, fence, Ordering};
+
+fn main() {
+    // Allowed fence ordering modes
+    fence(Ordering::Acquire);
+    fence(Ordering::Release);
+    fence(Ordering::AcqRel);
+    fence(Ordering::SeqCst);
+
+    // Disallowed fence ordering modes
+    fence(Ordering::Relaxed);
+
+    compiler_fence(Ordering::Acquire);
+    compiler_fence(Ordering::Release);
+    compiler_fence(Ordering::AcqRel);
+    compiler_fence(Ordering::SeqCst);
+    compiler_fence(Ordering::Relaxed);
+}
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_fence.stderr b/src/tools/clippy/tests/ui/atomic_ordering_fence.stderr
new file mode 100644
index 00000000000..3ceff27d9ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_fence.stderr
@@ -0,0 +1,19 @@
+error: memory fences cannot have `Relaxed` ordering
+  --> $DIR/atomic_ordering_fence.rs:13:11
+   |
+LL |     fence(Ordering::Relaxed);
+   |           ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+
+error: memory fences cannot have `Relaxed` ordering
+  --> $DIR/atomic_ordering_fence.rs:19:20
+   |
+LL |     compiler_fence(Ordering::Relaxed);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_int.rs b/src/tools/clippy/tests/ui/atomic_ordering_int.rs
new file mode 100644
index 00000000000..40a00ba3de3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_int.rs
@@ -0,0 +1,86 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, Ordering};
+
+fn main() {
+    // `AtomicI8` test cases
+    let x = AtomicI8::new(0);
+
+    // Allowed load ordering modes
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+
+    // Disallowed load ordering modes
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    // Allowed store ordering modes
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+
+    // Disallowed store ordering modes
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicI16` test cases
+    let x = AtomicI16::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicI32` test cases
+    let x = AtomicI32::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicI64` test cases
+    let x = AtomicI64::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicIsize` test cases
+    let x = AtomicIsize::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+}
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_int.stderr b/src/tools/clippy/tests/ui/atomic_ordering_int.stderr
new file mode 100644
index 00000000000..bbaf234d3c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_int.stderr
@@ -0,0 +1,163 @@
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:15:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:16:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:24:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:25:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:33:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:34:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:39:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:40:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:48:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:49:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:54:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:55:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:63:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:64:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:69:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:70:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:78:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:79:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:84:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_int.rs:85:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_ptr.rs b/src/tools/clippy/tests/ui/atomic_ordering_ptr.rs
new file mode 100644
index 00000000000..ecbb05c7fbc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_ptr.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+fn main() {
+    let ptr = &mut 5;
+    let other_ptr = &mut 10;
+    let x = AtomicPtr::new(ptr);
+
+    // Allowed load ordering modes
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+
+    // Disallowed load ordering modes
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    // Allowed store ordering modes
+    x.store(other_ptr, Ordering::Release);
+    x.store(other_ptr, Ordering::SeqCst);
+    x.store(other_ptr, Ordering::Relaxed);
+
+    // Disallowed store ordering modes
+    x.store(other_ptr, Ordering::Acquire);
+    x.store(other_ptr, Ordering::AcqRel);
+}
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_ptr.stderr b/src/tools/clippy/tests/ui/atomic_ordering_ptr.stderr
new file mode 100644
index 00000000000..558ae55518d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_ptr.stderr
@@ -0,0 +1,35 @@
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_ptr.rs:16:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_ptr.rs:17:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_ptr.rs:25:24
+   |
+LL |     x.store(other_ptr, Ordering::Acquire);
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_ptr.rs:26:24
+   |
+LL |     x.store(other_ptr, Ordering::AcqRel);
+   |                        ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_uint.rs b/src/tools/clippy/tests/ui/atomic_ordering_uint.rs
new file mode 100644
index 00000000000..a0d5d7c4010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_uint.rs
@@ -0,0 +1,86 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering};
+
+fn main() {
+    // `AtomicU8` test cases
+    let x = AtomicU8::new(0);
+
+    // Allowed load ordering modes
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+
+    // Disallowed load ordering modes
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    // Allowed store ordering modes
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+
+    // Disallowed store ordering modes
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicU16` test cases
+    let x = AtomicU16::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicU32` test cases
+    let x = AtomicU32::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicU64` test cases
+    let x = AtomicU64::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+
+    // `AtomicUsize` test cases
+    let x = AtomicUsize::new(0);
+
+    let _ = x.load(Ordering::Acquire);
+    let _ = x.load(Ordering::SeqCst);
+    let _ = x.load(Ordering::Relaxed);
+    let _ = x.load(Ordering::Release);
+    let _ = x.load(Ordering::AcqRel);
+
+    x.store(1, Ordering::Release);
+    x.store(1, Ordering::SeqCst);
+    x.store(1, Ordering::Relaxed);
+    x.store(1, Ordering::Acquire);
+    x.store(1, Ordering::AcqRel);
+}
diff --git a/src/tools/clippy/tests/ui/atomic_ordering_uint.stderr b/src/tools/clippy/tests/ui/atomic_ordering_uint.stderr
new file mode 100644
index 00000000000..5703135bcf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/atomic_ordering_uint.stderr
@@ -0,0 +1,163 @@
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:15:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:16:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:24:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:25:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:33:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:34:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:39:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:40:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:48:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:49:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:54:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:55:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:63:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:64:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:69:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:70:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:78:20
+   |
+LL |     let _ = x.load(Ordering::Release);
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic loads cannot have `Release` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:79:20
+   |
+LL |     let _ = x.load(Ordering::AcqRel);
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:84:16
+   |
+LL |     x.store(1, Ordering::Acquire);
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: atomic stores cannot have `Acquire` and `AcqRel` ordering
+  --> $DIR/atomic_ordering_uint.rs:85:16
+   |
+LL |     x.store(1, Ordering::AcqRel);
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs
new file mode 100644
index 00000000000..91b65a43be7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/attrs.rs
@@ -0,0 +1,43 @@
+#![warn(clippy::inline_always, clippy::deprecated_semver)]
+#![allow(clippy::assertions_on_constants)]
+#[inline(always)]
+fn test_attr_lint() {
+    assert!(true)
+}
+
+#[inline(always)]
+fn false_positive_expr() {
+    unreachable!()
+}
+
+#[inline(always)]
+fn false_positive_stmt() {
+    unreachable!();
+}
+
+#[inline(always)]
+fn empty_and_false_positive_stmt() {
+    unreachable!();
+}
+
+#[deprecated(since = "forever")]
+pub const SOME_CONST: u8 = 42;
+
+#[deprecated(since = "1")]
+pub const ANOTHER_CONST: u8 = 23;
+
+#[deprecated(since = "0.1.1")]
+pub const YET_ANOTHER_CONST: u8 = 0;
+
+fn main() {
+    test_attr_lint();
+    if false {
+        false_positive_expr()
+    }
+    if false {
+        false_positive_stmt()
+    }
+    if false {
+        empty_and_false_positive_stmt()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr
new file mode 100644
index 00000000000..39ddf6f226d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/attrs.stderr
@@ -0,0 +1,24 @@
+error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
+  --> $DIR/attrs.rs:3:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::inline-always` implied by `-D warnings`
+
+error: the since field must contain a semver-compliant version
+  --> $DIR/attrs.rs:23:14
+   |
+LL | #[deprecated(since = "forever")]
+   |              ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::deprecated-semver` implied by `-D warnings`
+
+error: the since field must contain a semver-compliant version
+  --> $DIR/attrs.rs:26:14
+   |
+LL | #[deprecated(since = "1")]
+   |              ^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui/author.rs
new file mode 100644
index 00000000000..0a1be356896
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author.rs
@@ -0,0 +1,4 @@
+fn main() {
+    #[clippy::author]
+    let x: char = 0x45 as char;
+}
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
new file mode 100644
index 00000000000..211d11c7c1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -0,0 +1,14 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Cast(ref expr, ref cast_ty) = init.kind;
+    if let TyKind::Path(ref qp) = cast_ty.kind;
+    if match_qpath(qp, &["char"]);
+    if let ExprKind::Lit(ref lit) = expr.kind;
+    if let LitKind::Int(69, _) = lit.node;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if name.as_str() == "x";
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui/author/blocks.rs
new file mode 100644
index 00000000000..a8068436b70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/blocks.rs
@@ -0,0 +1,16 @@
+#![feature(stmt_expr_attributes)]
+#![allow(redundant_semicolons, clippy::no_effect)]
+
+#[rustfmt::skip]
+fn main() {
+    #[clippy::author]
+    {
+        ;;;;
+    }
+}
+
+#[clippy::author]
+fn foo() {
+    let x = 42i32;
+    -x;
+}
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
new file mode 100644
index 00000000000..c8ef75e48fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -0,0 +1,13 @@
+if_chain! {
+    if let ExprKind::Block(ref block) = expr.kind;
+    if let Some(trailing_expr) = &block.expr;
+    if block.stmts.len() == 0;
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui/author/call.rs
new file mode 100644
index 00000000000..e99c3c41dc4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/call.rs
@@ -0,0 +1,4 @@
+fn main() {
+    #[clippy::author]
+    let _ = ::std::cmp::min(3, 4);
+}
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
new file mode 100644
index 00000000000..4dccf666631
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -0,0 +1,16 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Call(ref func, ref args) = init.kind;
+    if let ExprKind::Path(ref path) = func.kind;
+    if match_qpath(path, &["{{root}}", "std", "cmp", "min"]);
+    if args.len() == 2;
+    if let ExprKind::Lit(ref lit) = args[0].kind;
+    if let LitKind::Int(3, _) = lit.node;
+    if let ExprKind::Lit(ref lit1) = args[1].kind;
+    if let LitKind::Int(4, _) = lit1.node;
+    if let PatKind::Wild = local.pat.kind;
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/for_loop.rs b/src/tools/clippy/tests/ui/author/for_loop.rs
new file mode 100644
index 00000000000..b3dec876535
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/for_loop.rs
@@ -0,0 +1,8 @@
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+    #[clippy::author]
+    for y in 0..10 {
+        let z = y;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout
new file mode 100644
index 00000000000..81ede955347
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/for_loop.stdout
@@ -0,0 +1,62 @@
+if_chain! {
+    if let ExprKind::DropTemps(ref expr) = expr.kind;
+    if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
+    if let ExprKind::Call(ref func, ref args) = expr1.kind;
+    if let ExprKind::Path(ref path) = func.kind;
+    if match_qpath(path, &["{{root}}", "std", "iter", "IntoIterator", "into_iter"]);
+    if args.len() == 1;
+    if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
+    if match_qpath(path1, &["{{root}}", "std", "ops", "Range"]);
+    if fields.len() == 2;
+    // unimplemented: field checks
+    if arms.len() == 1;
+    if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.kind;
+    if let Some(trailing_expr) = &body.expr;
+    if body.stmts.len() == 4;
+    if let StmtKind::Local(ref local) = body.stmts[0].kind;
+    if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local.pat.kind;
+    if name.as_str() == "__next";
+    if let StmtKind::Expr(ref e, _) = body.stmts[1].kind
+    if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
+    if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
+    if let ExprKind::Path(ref path2) = func1.kind;
+    if match_qpath(path2, &["{{root}}", "std", "iter", "Iterator", "next"]);
+    if args1.len() == 1;
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
+    if let ExprKind::Path(ref path3) = inner.kind;
+    if match_qpath(path3, &["iter"]);
+    if arms1.len() == 2;
+    if let ExprKind::Assign(ref target, ref value, ref _span) = arms1[0].body.kind;
+    if let ExprKind::Path(ref path4) = target.kind;
+    if match_qpath(path4, &["__next"]);
+    if let ExprKind::Path(ref path5) = value.kind;
+    if match_qpath(path5, &["val"]);
+    if let PatKind::TupleStruct(ref path6, ref fields1, None) = arms1[0].pat.kind;
+    if match_qpath(path6, &["{{root}}", "std", "option", "Option", "Some"]);
+    if fields1.len() == 1;
+    // unimplemented: field checks
+    if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
+    if let PatKind::Path(ref path7) = arms1[1].pat.kind;
+    if match_qpath(path7, &["{{root}}", "std", "option", "Option", "None"]);
+    if let StmtKind::Local(ref local1) = body.stmts[2].kind;
+    if let Some(ref init) = local1.init;
+    if let ExprKind::Path(ref path8) = init.kind;
+    if match_qpath(path8, &["__next"]);
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+    if name1.as_str() == "y";
+    if let StmtKind::Expr(ref e1, _) = body.stmts[3].kind
+    if let ExprKind::Block(ref block) = e1.kind;
+    if let Some(trailing_expr1) = &block.expr;
+    if block.stmts.len() == 1;
+    if let StmtKind::Local(ref local2) = block.stmts[0].kind;
+    if let Some(ref init1) = local2.init;
+    if let ExprKind::Path(ref path9) = init1.kind;
+    if match_qpath(path9, &["y"]);
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local2.pat.kind;
+    if name2.as_str() == "z";
+    if let PatKind::Binding(BindingAnnotation::Mutable, _, name3, None) = arms[0].pat.kind;
+    if name3.as_str() == "iter";
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui/author/if.rs
new file mode 100644
index 00000000000..2e9cb1466d0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/if.rs
@@ -0,0 +1,10 @@
+#[allow(clippy::all)]
+
+fn main() {
+    #[clippy::author]
+    let _ = if true {
+        1 == 1;
+    } else {
+        2 == 2;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
new file mode 100644
index 00000000000..c18d035953e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -0,0 +1,31 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.kind;
+    if let Some(ref init) = local.init;
+    if let Some((ref cond, ref then, Some(else_))) = higher::if_block(&init);
+    if let ExprKind::Block(ref block) = else_.kind;
+    if let Some(trailing_expr) = &block.expr;
+    if block.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
+    if let ExprKind::Binary(ref op, ref left, ref right) = e.kind;
+    if BinOpKind::Eq == op.node;
+    if let ExprKind::Lit(ref lit) = left.kind;
+    if let LitKind::Int(2, _) = lit.node;
+    if let ExprKind::Lit(ref lit1) = right.kind;
+    if let LitKind::Int(2, _) = lit1.node;
+    if let ExprKind::Lit(ref lit2) = cond.kind;
+    if let LitKind::Bool(true) = lit2.node;
+    if let ExprKind::Block(ref block1) = then.kind;
+    if let Some(trailing_expr1) = &block1.expr;
+    if block1.stmts.len() == 1;
+    if let StmtKind::Semi(ref e1, _) = block1.stmts[0].kind
+    if let ExprKind::Binary(ref op1, ref left1, ref right1) = e1.kind;
+    if BinOpKind::Eq == op1.node;
+    if let ExprKind::Lit(ref lit3) = left1.kind;
+    if let LitKind::Int(1, _) = lit3.node;
+    if let ExprKind::Lit(ref lit4) = right1.kind;
+    if let LitKind::Int(1, _) = lit4.node;
+    if let PatKind::Wild = local.pat.kind;
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui/author/issue_3849.rs
new file mode 100644
index 00000000000..bae4570e539
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/issue_3849.rs
@@ -0,0 +1,14 @@
+#![allow(dead_code)]
+#![allow(clippy::zero_ptr)]
+#![allow(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::transmuting_null)]
+
+pub const ZPTR: *const usize = 0 as *const _;
+
+fn main() {
+    unsafe {
+        #[clippy::author]
+        let _: &i32 = std::mem::transmute(ZPTR);
+        let _: &i32 = std::mem::transmute(0 as *const i32);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
new file mode 100644
index 00000000000..65f93f3cdc0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -0,0 +1,14 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Call(ref func, ref args) = init.kind;
+    if let ExprKind::Path(ref path) = func.kind;
+    if match_qpath(path, &["std", "mem", "transmute"]);
+    if args.len() == 1;
+    if let ExprKind::Path(ref path1) = args[0].kind;
+    if match_qpath(path1, &["ZPTR"]);
+    if let PatKind::Wild = local.pat.kind;
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui/author/matches.rs
new file mode 100644
index 00000000000..674e07ec2d3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/matches.rs
@@ -0,0 +1,13 @@
+#![allow(clippy::let_and_return)]
+
+fn main() {
+    #[clippy::author]
+    let a = match 42 {
+        16 => 5,
+        17 => {
+            let x = 3;
+            x
+        },
+        _ => 1,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
new file mode 100644
index 00000000000..2e8f8227dca
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -0,0 +1,33 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Match(ref expr, ref arms, MatchSource::Normal) = init.kind;
+    if let ExprKind::Lit(ref lit) = expr.kind;
+    if let LitKind::Int(42, _) = lit.node;
+    if arms.len() == 3;
+    if let ExprKind::Lit(ref lit1) = arms[0].body.kind;
+    if let LitKind::Int(5, _) = lit1.node;
+    if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind
+    if let ExprKind::Lit(ref lit2) = lit_expr.kind;
+    if let LitKind::Int(16, _) = lit2.node;
+    if let ExprKind::Block(ref block) = arms[1].body.kind;
+    if let Some(trailing_expr) = &block.expr;
+    if block.stmts.len() == 1;
+    if let StmtKind::Local(ref local1) = block.stmts[0].kind;
+    if let Some(ref init1) = local1.init;
+    if let ExprKind::Lit(ref lit3) = init1.kind;
+    if let LitKind::Int(3, _) = lit3.node;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
+    if name.as_str() == "x";
+    if let PatKind::Lit(ref lit_expr1) = arms[1].pat.kind
+    if let ExprKind::Lit(ref lit4) = lit_expr1.kind;
+    if let LitKind::Int(17, _) = lit4.node;
+    if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
+    if let LitKind::Int(1, _) = lit5.node;
+    if let PatKind::Wild = arms[2].pat.kind;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if name1.as_str() == "a";
+    then {
+        // report your lint here
+    }
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs b/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs
new file mode 100644
index 00000000000..869672d1eda
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/doc_unsafe_macros.rs
@@ -0,0 +1,8 @@
+#[macro_export]
+macro_rules! undocd_unsafe {
+    () => {
+        pub unsafe fn oy_vey() {
+            unimplemented!();
+        }
+    };
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs b/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs
new file mode 100644
index 00000000000..1eb77c53183
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/implicit_hasher_macros.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! implicit_hasher_fn {
+    () => {
+        pub fn f(input: &HashMap<u32, u32>) {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
new file mode 100644
index 00000000000..0bbb9534928
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -0,0 +1,58 @@
+#![allow(dead_code)]
+
+//! Used to test that certain lints don't trigger in imported external macros
+
+#[macro_export]
+macro_rules! foofoo {
+    () => {
+        loop {}
+    };
+}
+
+#[macro_export]
+macro_rules! must_use_unit {
+    () => {
+        #[must_use]
+        fn foo() {}
+    };
+}
+
+#[macro_export]
+macro_rules! try_err {
+    () => {
+        pub fn try_err_fn() -> Result<i32, i32> {
+            let err: i32 = 1;
+            // To avoid warnings during rustfix
+            if true {
+                Err(err)?
+            } else {
+                Ok(2)
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! string_add {
+    () => {
+        let y = "".to_owned();
+        let z = y + "...";
+    };
+}
+
+#[macro_export]
+macro_rules! take_external {
+    ($s:expr) => {
+        std::mem::replace($s, Default::default())
+    };
+}
+
+#[macro_export]
+macro_rules! option_env_unwrap_external {
+    ($env: expr) => {
+        option_env!($env).unwrap()
+    };
+    ($env: expr, $message: expr) => {
+        option_env!($env).expect($message)
+    };
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs b/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs
new file mode 100644
index 00000000000..ed11c41e21c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs
@@ -0,0 +1,51 @@
+#![allow(dead_code, unused_variables)]
+
+/// Utility macro to test linting behavior in `option_methods()`
+/// The lints included in `option_methods()` should not lint if the call to map is partially
+/// within a macro
+#[macro_export]
+macro_rules! opt_map {
+    ($opt:expr, $map:expr) => {
+        ($opt).map($map)
+    };
+}
+
+/// Struct to generate false positive for Iterator-based lints
+#[derive(Copy, Clone)]
+pub struct IteratorFalsePositives {
+    pub foo: u32,
+}
+
+impl IteratorFalsePositives {
+    pub fn filter(self) -> IteratorFalsePositives {
+        self
+    }
+
+    pub fn next(self) -> IteratorFalsePositives {
+        self
+    }
+
+    pub fn find(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn position(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn rposition(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn nth(self, n: usize) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn skip(self, _: usize) -> IteratorFalsePositives {
+        self
+    }
+
+    pub fn skip_while(self) -> IteratorFalsePositives {
+        self
+    }
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
new file mode 100644
index 00000000000..21bb5b01e02
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -0,0 +1,22 @@
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_derive(DeriveSomething)]
+pub fn derive(_: TokenStream) -> TokenStream {
+    // Shound not trigger `used_underscore_binding`
+    let _inside_derive = 1;
+    assert_eq!(_inside_derive, _inside_derive);
+
+    let output = quote! {
+        // Should not trigger `useless_attribute`
+        #[allow(dead_code)]
+        extern crate rustc_middle;
+    };
+    output
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/use_self_macro.rs b/src/tools/clippy/tests/ui/auxiliary/use_self_macro.rs
new file mode 100644
index 00000000000..a8a85b4baef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/use_self_macro.rs
@@ -0,0 +1,15 @@
+macro_rules! use_self {
+    (
+        impl $ty:ident {
+            fn func(&$this:ident) {
+                [fields($($field:ident)*)]
+            }
+        }
+    ) => (
+        impl  $ty {
+            fn func(&$this) {
+                let $ty { $($field),* } = $this;
+            }
+        }
+    )
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs b/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
new file mode 100644
index 00000000000..414477aedd7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
@@ -0,0 +1,21 @@
+pub use crate::extern_exports::*;
+
+pub fn extern_foo() {}
+pub fn extern_bar() {}
+
+pub struct ExternA;
+
+pub mod inner {
+    pub mod inner_for_self_import {
+        pub fn inner_extern_foo() {}
+        pub fn inner_extern_bar() {}
+    }
+}
+
+mod extern_exports {
+    pub fn extern_exported() {}
+    pub struct ExternExportedStruct;
+    pub enum ExternExportedEnum {
+        A,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs
new file mode 100644
index 00000000000..5c1fdd83efb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/await_holding_lock.rs
@@ -0,0 +1,64 @@
+// edition:2018
+#![warn(clippy::await_holding_lock)]
+
+use std::sync::Mutex;
+
+async fn bad(x: &Mutex<u32>) -> u32 {
+    let guard = x.lock().unwrap();
+    baz().await
+}
+
+async fn good(x: &Mutex<u32>) -> u32 {
+    {
+        let guard = x.lock().unwrap();
+        let y = *guard + 1;
+    }
+    baz().await;
+    let guard = x.lock().unwrap();
+    47
+}
+
+async fn baz() -> u32 {
+    42
+}
+
+async fn also_bad(x: &Mutex<u32>) -> u32 {
+    let first = baz().await;
+
+    let guard = x.lock().unwrap();
+
+    let second = baz().await;
+
+    let third = baz().await;
+
+    first + second + third
+}
+
+async fn not_good(x: &Mutex<u32>) -> u32 {
+    let first = baz().await;
+
+    let second = {
+        let guard = x.lock().unwrap();
+        baz().await
+    };
+
+    let third = baz().await;
+
+    first + second + third
+}
+
+fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
+    async move {
+        let guard = x.lock().unwrap();
+        baz().await
+    }
+}
+
+fn main() {
+    let m = Mutex::new(100);
+    good(&m);
+    bad(&m);
+    also_bad(&m);
+    not_good(&m);
+    block_bad(&m);
+}
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
new file mode 100644
index 00000000000..8c47cb37d8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -0,0 +1,63 @@
+error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.
+  --> $DIR/await_holding_lock.rs:7:9
+   |
+LL |     let guard = x.lock().unwrap();
+   |         ^^^^^
+   |
+   = note: `-D clippy::await-holding-lock` implied by `-D warnings`
+note: these are all the await points this lock is held through
+  --> $DIR/await_holding_lock.rs:7:5
+   |
+LL | /     let guard = x.lock().unwrap();
+LL | |     baz().await
+LL | | }
+   | |_^
+
+error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.
+  --> $DIR/await_holding_lock.rs:28:9
+   |
+LL |     let guard = x.lock().unwrap();
+   |         ^^^^^
+   |
+note: these are all the await points this lock is held through
+  --> $DIR/await_holding_lock.rs:28:5
+   |
+LL | /     let guard = x.lock().unwrap();
+LL | |
+LL | |     let second = baz().await;
+LL | |
+...  |
+LL | |     first + second + third
+LL | | }
+   | |_^
+
+error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.
+  --> $DIR/await_holding_lock.rs:41:13
+   |
+LL |         let guard = x.lock().unwrap();
+   |             ^^^^^
+   |
+note: these are all the await points this lock is held through
+  --> $DIR/await_holding_lock.rs:41:9
+   |
+LL | /         let guard = x.lock().unwrap();
+LL | |         baz().await
+LL | |     };
+   | |_____^
+
+error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.
+  --> $DIR/await_holding_lock.rs:52:13
+   |
+LL |         let guard = x.lock().unwrap();
+   |             ^^^^^
+   |
+note: these are all the await points this lock is held through
+  --> $DIR/await_holding_lock.rs:52:9
+   |
+LL | /         let guard = x.lock().unwrap();
+LL | |         baz().await
+LL | |     }
+   | |_____^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/bit_masks.rs b/src/tools/clippy/tests/ui/bit_masks.rs
new file mode 100644
index 00000000000..cfb493fb52a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bit_masks.rs
@@ -0,0 +1,63 @@
+const THREE_BITS: i64 = 7;
+const EVEN_MORE_REDIRECTION: i64 = THREE_BITS;
+
+#[warn(clippy::bad_bit_mask)]
+#[allow(
+    clippy::ineffective_bit_mask,
+    clippy::identity_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
+fn main() {
+    let x = 5;
+
+    x & 0 == 0;
+    x & 1 == 1; //ok, distinguishes bit 0
+    x & 1 == 0; //ok, compared with zero
+    x & 2 == 1;
+    x | 0 == 0; //ok, equals x == 0 (maybe warn?)
+    x | 1 == 3; //ok, equals x == 2 || x == 3
+    x | 3 == 3; //ok, equals x <= 3
+    x | 3 == 2;
+
+    x & 1 > 1;
+    x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
+    x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
+    x | 1 > 1; // ok (if a bit silly), equals x > 1
+    x | 2 > 1;
+    x | 2 <= 2; // ok (if a bit silly), equals x <= 2
+
+    x & 192 == 128; // ok, tests for bit 7 and not bit 6
+    x & 0xffc0 == 0xfe80; // ok
+
+    // this also now works with constants
+    x & THREE_BITS == 8;
+    x | EVEN_MORE_REDIRECTION < 7;
+
+    0 & x == 0;
+    1 | x > 1;
+
+    // and should now also match uncommon usage
+    1 < 2 | x;
+    2 == 3 | x;
+    1 == x & 2;
+
+    x | 1 > 2; // no error, because we allowed ineffective bit masks
+    ineffective();
+}
+
+#[warn(clippy::ineffective_bit_mask)]
+#[allow(clippy::bad_bit_mask, clippy::no_effect, clippy::unnecessary_operation)]
+fn ineffective() {
+    let x = 5;
+
+    x | 1 > 3;
+    x | 1 < 4;
+    x | 1 <= 3;
+    x | 1 >= 8;
+
+    x | 1 > 2; // not an error (yet), better written as x >= 2
+    x | 1 >= 7; // not an error (yet), better written as x >= 6
+    x | 3 > 4; // not an error (yet), better written as x >= 4
+    x | 4 <= 19;
+}
diff --git a/src/tools/clippy/tests/ui/bit_masks.stderr b/src/tools/clippy/tests/ui/bit_masks.stderr
new file mode 100644
index 00000000000..dc5ad6dfbdf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bit_masks.stderr
@@ -0,0 +1,110 @@
+error: &-masking with zero
+  --> $DIR/bit_masks.rs:14:5
+   |
+LL |     x & 0 == 0;
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::bad-bit-mask` implied by `-D warnings`
+
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/bit_masks.rs:14:5
+   |
+LL |     x & 0 == 0;
+   |     ^^^^^
+   |
+   = note: `#[deny(clippy::erasing_op)]` on by default
+
+error: incompatible bit mask: `_ & 2` can never be equal to `1`
+  --> $DIR/bit_masks.rs:17:5
+   |
+LL |     x & 2 == 1;
+   |     ^^^^^^^^^^
+
+error: incompatible bit mask: `_ | 3` can never be equal to `2`
+  --> $DIR/bit_masks.rs:21:5
+   |
+LL |     x | 3 == 2;
+   |     ^^^^^^^^^^
+
+error: incompatible bit mask: `_ & 1` will never be higher than `1`
+  --> $DIR/bit_masks.rs:23:5
+   |
+LL |     x & 1 > 1;
+   |     ^^^^^^^^^
+
+error: incompatible bit mask: `_ | 2` will always be higher than `1`
+  --> $DIR/bit_masks.rs:27:5
+   |
+LL |     x | 2 > 1;
+   |     ^^^^^^^^^
+
+error: incompatible bit mask: `_ & 7` can never be equal to `8`
+  --> $DIR/bit_masks.rs:34:5
+   |
+LL |     x & THREE_BITS == 8;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: incompatible bit mask: `_ | 7` will never be lower than `7`
+  --> $DIR/bit_masks.rs:35:5
+   |
+LL |     x | EVEN_MORE_REDIRECTION < 7;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: &-masking with zero
+  --> $DIR/bit_masks.rs:37:5
+   |
+LL |     0 & x == 0;
+   |     ^^^^^^^^^^
+
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/bit_masks.rs:37:5
+   |
+LL |     0 & x == 0;
+   |     ^^^^^
+
+error: incompatible bit mask: `_ | 2` will always be higher than `1`
+  --> $DIR/bit_masks.rs:41:5
+   |
+LL |     1 < 2 | x;
+   |     ^^^^^^^^^
+
+error: incompatible bit mask: `_ | 3` can never be equal to `2`
+  --> $DIR/bit_masks.rs:42:5
+   |
+LL |     2 == 3 | x;
+   |     ^^^^^^^^^^
+
+error: incompatible bit mask: `_ & 2` can never be equal to `1`
+  --> $DIR/bit_masks.rs:43:5
+   |
+LL |     1 == x & 2;
+   |     ^^^^^^^^^^
+
+error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly
+  --> $DIR/bit_masks.rs:54:5
+   |
+LL |     x | 1 > 3;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::ineffective-bit-mask` implied by `-D warnings`
+
+error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly
+  --> $DIR/bit_masks.rs:55:5
+   |
+LL |     x | 1 < 4;
+   |     ^^^^^^^^^
+
+error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly
+  --> $DIR/bit_masks.rs:56:5
+   |
+LL |     x | 1 <= 3;
+   |     ^^^^^^^^^^
+
+error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared directly
+  --> $DIR/bit_masks.rs:57:5
+   |
+LL |     x | 1 >= 8;
+   |     ^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/blacklisted_name.rs
new file mode 100644
index 00000000000..ca9d8d16b78
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blacklisted_name.rs
@@ -0,0 +1,40 @@
+#![allow(
+    dead_code,
+    clippy::similar_names,
+    clippy::single_match,
+    clippy::toplevel_ref_arg,
+    unused_mut,
+    unused_variables
+)]
+#![warn(clippy::blacklisted_name)]
+
+fn test(foo: ()) {}
+
+fn main() {
+    let foo = 42;
+    let bar = 42;
+    let baz = 42;
+
+    let barb = 42;
+    let barbaric = 42;
+
+    match (42, Some(1337), Some(0)) {
+        (foo, Some(bar), baz @ Some(_)) => (),
+        _ => (),
+    }
+}
+
+fn issue_1647(mut foo: u8) {
+    let mut bar = 0;
+    if let Some(mut baz) = Some(42) {}
+}
+
+fn issue_1647_ref() {
+    let ref bar = 0;
+    if let Some(ref baz) = Some(42) {}
+}
+
+fn issue_1647_ref_mut() {
+    let ref mut bar = 0;
+    if let Some(ref mut baz) = Some(42) {}
+}
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.stderr b/src/tools/clippy/tests/ui/blacklisted_name.stderr
new file mode 100644
index 00000000000..44123829fb0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blacklisted_name.stderr
@@ -0,0 +1,88 @@
+error: use of a blacklisted/placeholder name `foo`
+  --> $DIR/blacklisted_name.rs:11:9
+   |
+LL | fn test(foo: ()) {}
+   |         ^^^
+   |
+   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
+
+error: use of a blacklisted/placeholder name `foo`
+  --> $DIR/blacklisted_name.rs:14:9
+   |
+LL |     let foo = 42;
+   |         ^^^
+
+error: use of a blacklisted/placeholder name `bar`
+  --> $DIR/blacklisted_name.rs:15:9
+   |
+LL |     let bar = 42;
+   |         ^^^
+
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:16:9
+   |
+LL |     let baz = 42;
+   |         ^^^
+
+error: use of a blacklisted/placeholder name `foo`
+  --> $DIR/blacklisted_name.rs:22:10
+   |
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
+   |          ^^^
+
+error: use of a blacklisted/placeholder name `bar`
+  --> $DIR/blacklisted_name.rs:22:20
+   |
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
+   |                    ^^^
+
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:22:26
+   |
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
+   |                          ^^^
+
+error: use of a blacklisted/placeholder name `foo`
+  --> $DIR/blacklisted_name.rs:27:19
+   |
+LL | fn issue_1647(mut foo: u8) {
+   |                   ^^^
+
+error: use of a blacklisted/placeholder name `bar`
+  --> $DIR/blacklisted_name.rs:28:13
+   |
+LL |     let mut bar = 0;
+   |             ^^^
+
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:29:21
+   |
+LL |     if let Some(mut baz) = Some(42) {}
+   |                     ^^^
+
+error: use of a blacklisted/placeholder name `bar`
+  --> $DIR/blacklisted_name.rs:33:13
+   |
+LL |     let ref bar = 0;
+   |             ^^^
+
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:34:21
+   |
+LL |     if let Some(ref baz) = Some(42) {}
+   |                     ^^^
+
+error: use of a blacklisted/placeholder name `bar`
+  --> $DIR/blacklisted_name.rs:38:17
+   |
+LL |     let ref mut bar = 0;
+   |                 ^^^
+
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:39:25
+   |
+LL |     if let Some(ref mut baz) = Some(42) {}
+   |                         ^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/block_in_if_condition.fixed b/src/tools/clippy/tests/ui/block_in_if_condition.fixed
new file mode 100644
index 00000000000..955801e40f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/block_in_if_condition.fixed
@@ -0,0 +1,75 @@
+// run-rustfix
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![allow(unused, clippy::let_and_return)]
+#![warn(clippy::nonminimal_bool)]
+
+macro_rules! blocky {
+    () => {{
+        true
+    }};
+}
+
+macro_rules! blocky_too {
+    () => {{
+        let r = true;
+        r
+    }};
+}
+
+fn macro_if() {
+    if blocky!() {}
+
+    if blocky_too!() {}
+}
+
+fn condition_has_block() -> i32 {
+    let res = {
+        let x = 3;
+        x == 3
+    }; if res {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_has_block_with_single_expression() -> i32 {
+    if true {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_is_normal() -> i32 {
+    let x = 3;
+    if x == 3 {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_is_unsafe_block() {
+    let a: i32 = 1;
+
+    // this should not warn because the condition is an unsafe block
+    if unsafe { 1u32 == std::mem::transmute(a) } {
+        println!("1u32 == a");
+    }
+}
+
+fn block_in_assert() {
+    let opt = Some(42);
+    assert!(opt
+        .as_ref()
+        .and_then(|val| {
+            let mut v = val * 2;
+            v -= 1;
+            Some(v * 3)
+        })
+        .is_some());
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/block_in_if_condition.rs b/src/tools/clippy/tests/ui/block_in_if_condition.rs
new file mode 100644
index 00000000000..a6ea01d5fc5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/block_in_if_condition.rs
@@ -0,0 +1,75 @@
+// run-rustfix
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![allow(unused, clippy::let_and_return)]
+#![warn(clippy::nonminimal_bool)]
+
+macro_rules! blocky {
+    () => {{
+        true
+    }};
+}
+
+macro_rules! blocky_too {
+    () => {{
+        let r = true;
+        r
+    }};
+}
+
+fn macro_if() {
+    if blocky!() {}
+
+    if blocky_too!() {}
+}
+
+fn condition_has_block() -> i32 {
+    if {
+        let x = 3;
+        x == 3
+    } {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_has_block_with_single_expression() -> i32 {
+    if { true } {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_is_normal() -> i32 {
+    let x = 3;
+    if true && x == 3 {
+        6
+    } else {
+        10
+    }
+}
+
+fn condition_is_unsafe_block() {
+    let a: i32 = 1;
+
+    // this should not warn because the condition is an unsafe block
+    if unsafe { 1u32 == std::mem::transmute(a) } {
+        println!("1u32 == a");
+    }
+}
+
+fn block_in_assert() {
+    let opt = Some(42);
+    assert!(opt
+        .as_ref()
+        .and_then(|val| {
+            let mut v = val * 2;
+            v -= 1;
+            Some(v * 3)
+        })
+        .is_some());
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/block_in_if_condition.stderr b/src/tools/clippy/tests/ui/block_in_if_condition.stderr
new file mode 100644
index 00000000000..b0a0a276c89
--- /dev/null
+++ b/src/tools/clippy/tests/ui/block_in_if_condition.stderr
@@ -0,0 +1,36 @@
+error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+  --> $DIR/block_in_if_condition.rs:27:5
+   |
+LL | /     if {
+LL | |         let x = 3;
+LL | |         x == 3
+LL | |     } {
+   | |_____^
+   |
+   = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings`
+help: try
+   |
+LL |     let res = {
+LL |         let x = 3;
+LL |         x == 3
+LL |     }; if res {
+   |
+
+error: omit braces around single expression condition
+  --> $DIR/block_in_if_condition.rs:38:8
+   |
+LL |     if { true } {
+   |        ^^^^^^^^ help: try: `true`
+   |
+   = note: `-D clippy::block-in-if-condition-expr` implied by `-D warnings`
+
+error: this boolean expression can be simplified
+  --> $DIR/block_in_if_condition.rs:47:8
+   |
+LL |     if true && x == 3 {
+   |        ^^^^^^^^^^^^^^ help: try: `x == 3`
+   |
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/block_in_if_condition_closure.rs b/src/tools/clippy/tests/ui/block_in_if_condition_closure.rs
new file mode 100644
index 00000000000..bac3eda5e7f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/block_in_if_condition_closure.rs
@@ -0,0 +1,48 @@
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![allow(unused, clippy::let_and_return)]
+
+fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
+    pfn(val)
+}
+
+fn pred_test() {
+    let v = 3;
+    let sky = "blue";
+    // This is a sneaky case, where the block isn't directly in the condition,
+    // but is actually nside a closure that the condition is using.
+    // The same principle applies -- add some extra expressions to make sure
+    // linter isn't confused by them.
+    if v == 3
+        && sky == "blue"
+        && predicate(
+            |x| {
+                let target = 3;
+                x == target
+            },
+            v,
+        )
+    {}
+
+    if predicate(
+        |x| {
+            let target = 3;
+            x == target
+        },
+        v,
+    ) {}
+}
+
+fn closure_without_block() {
+    if predicate(|x| x == 3, 6) {}
+}
+
+fn macro_in_closure() {
+    let option = Some(true);
+
+    if option.unwrap_or_else(|| unimplemented!()) {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/block_in_if_condition_closure.stderr b/src/tools/clippy/tests/ui/block_in_if_condition_closure.stderr
new file mode 100644
index 00000000000..86cd24fe763
--- /dev/null
+++ b/src/tools/clippy/tests/ui/block_in_if_condition_closure.stderr
@@ -0,0 +1,24 @@
+error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+  --> $DIR/block_in_if_condition_closure.rs:19:17
+   |
+LL |               |x| {
+   |  _________________^
+LL | |                 let target = 3;
+LL | |                 x == target
+LL | |             },
+   | |_____________^
+   |
+   = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings`
+
+error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+  --> $DIR/block_in_if_condition_closure.rs:28:13
+   |
+LL |           |x| {
+   |  _____________^
+LL | |             let target = 3;
+LL | |             x == target
+LL | |         },
+   | |_________^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed
new file mode 100644
index 00000000000..91211764759
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_comparison.fixed
@@ -0,0 +1,129 @@
+// run-rustfix
+
+#[warn(clippy::bool_comparison)]
+fn main() {
+    let x = true;
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    let y = true;
+    if !x & y {
+        "yes"
+    } else {
+        "no"
+    };
+    if x & !y {
+        "yes"
+    } else {
+        "no"
+    };
+}
+
+#[allow(dead_code)]
+fn issue3703() {
+    struct Foo;
+    impl PartialEq<bool> for Foo {
+        fn eq(&self, _: &bool) -> bool {
+            true
+        }
+    }
+    impl PartialEq<Foo> for bool {
+        fn eq(&self, _: &Foo) -> bool {
+            true
+        }
+    }
+    impl PartialOrd<bool> for Foo {
+        fn partial_cmp(&self, _: &bool) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+    impl PartialOrd<Foo> for bool {
+        fn partial_cmp(&self, _: &Foo) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+
+    if Foo == true {}
+    if true == Foo {}
+    if Foo != true {}
+    if true != Foo {}
+    if Foo == false {}
+    if false == Foo {}
+    if Foo != false {}
+    if false != Foo {}
+    if Foo < false {}
+    if false < Foo {}
+}
+
+#[allow(dead_code)]
+fn issue4983() {
+    let a = true;
+    let b = false;
+
+    if a != b {};
+    if a != b {};
+    if a == b {};
+    if !a == !b {};
+
+    if b != a {};
+    if b != a {};
+    if b == a {};
+    if !b == !a {};
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs
new file mode 100644
index 00000000000..01ee35859f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_comparison.rs
@@ -0,0 +1,129 @@
+// run-rustfix
+
+#[warn(clippy::bool_comparison)]
+fn main() {
+    let x = true;
+    if x == true {
+        "yes"
+    } else {
+        "no"
+    };
+    if x == false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true == x {
+        "yes"
+    } else {
+        "no"
+    };
+    if false == x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x != true {
+        "yes"
+    } else {
+        "no"
+    };
+    if x != false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true != x {
+        "yes"
+    } else {
+        "no"
+    };
+    if false != x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x < true {
+        "yes"
+    } else {
+        "no"
+    };
+    if false < x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x > false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true > x {
+        "yes"
+    } else {
+        "no"
+    };
+    let y = true;
+    if x < y {
+        "yes"
+    } else {
+        "no"
+    };
+    if x > y {
+        "yes"
+    } else {
+        "no"
+    };
+}
+
+#[allow(dead_code)]
+fn issue3703() {
+    struct Foo;
+    impl PartialEq<bool> for Foo {
+        fn eq(&self, _: &bool) -> bool {
+            true
+        }
+    }
+    impl PartialEq<Foo> for bool {
+        fn eq(&self, _: &Foo) -> bool {
+            true
+        }
+    }
+    impl PartialOrd<bool> for Foo {
+        fn partial_cmp(&self, _: &bool) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+    impl PartialOrd<Foo> for bool {
+        fn partial_cmp(&self, _: &Foo) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+
+    if Foo == true {}
+    if true == Foo {}
+    if Foo != true {}
+    if true != Foo {}
+    if Foo == false {}
+    if false == Foo {}
+    if Foo != false {}
+    if false != Foo {}
+    if Foo < false {}
+    if false < Foo {}
+}
+
+#[allow(dead_code)]
+fn issue4983() {
+    let a = true;
+    let b = false;
+
+    if a == !b {};
+    if !a == b {};
+    if a == b {};
+    if !a == !b {};
+
+    if b == !a {};
+    if !b == a {};
+    if b == a {};
+    if !b == !a {};
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr
new file mode 100644
index 00000000000..eeb1f20ee89
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_comparison.stderr
@@ -0,0 +1,112 @@
+error: equality checks against true are unnecessary
+  --> $DIR/bool_comparison.rs:6:8
+   |
+LL |     if x == true {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |
+   = note: `-D clippy::bool-comparison` implied by `-D warnings`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/bool_comparison.rs:11:8
+   |
+LL |     if x == false {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: equality checks against true are unnecessary
+  --> $DIR/bool_comparison.rs:16:8
+   |
+LL |     if true == x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/bool_comparison.rs:21:8
+   |
+LL |     if false == x {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: inequality checks against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:26:8
+   |
+LL |     if x != true {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: inequality checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:31:8
+   |
+LL |     if x != false {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: inequality checks against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:36:8
+   |
+LL |     if true != x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: inequality checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:41:8
+   |
+LL |     if false != x {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: less than comparison against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:46:8
+   |
+LL |     if x < true {
+   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: greater than checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:51:8
+   |
+LL |     if false < x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: greater than checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:56:8
+   |
+LL |     if x > false {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: less than comparison against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:61:8
+   |
+LL |     if true > x {
+   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: order comparisons between booleans can be simplified
+  --> $DIR/bool_comparison.rs:67:8
+   |
+LL |     if x < y {
+   |        ^^^^^ help: try simplifying it as shown: `!x & y`
+
+error: order comparisons between booleans can be simplified
+  --> $DIR/bool_comparison.rs:72:8
+   |
+LL |     if x > y {
+   |        ^^^^^ help: try simplifying it as shown: `x & !y`
+
+error: This comparison might be written more concisely
+  --> $DIR/bool_comparison.rs:120:8
+   |
+LL |     if a == !b {};
+   |        ^^^^^^^ help: try simplifying it as shown: `a != b`
+
+error: This comparison might be written more concisely
+  --> $DIR/bool_comparison.rs:121:8
+   |
+LL |     if !a == b {};
+   |        ^^^^^^^ help: try simplifying it as shown: `a != b`
+
+error: This comparison might be written more concisely
+  --> $DIR/bool_comparison.rs:125:8
+   |
+LL |     if b == !a {};
+   |        ^^^^^^^ help: try simplifying it as shown: `b != a`
+
+error: This comparison might be written more concisely
+  --> $DIR/bool_comparison.rs:126:8
+   |
+LL |     if !b == a {};
+   |        ^^^^^^^ help: try simplifying it as shown: `b != a`
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
new file mode 100644
index 00000000000..1901de46ca8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -0,0 +1,99 @@
+#![deny(clippy::borrowed_box)]
+#![allow(clippy::blacklisted_name)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+pub fn test1(foo: &mut Box<bool>) {
+    // Although this function could be changed to "&mut bool",
+    // avoiding the Box, mutable references to boxes are not
+    // flagged by this lint.
+    //
+    // This omission is intentional: By passing a mutable Box,
+    // the memory location of the pointed-to object could be
+    // modified. By passing a mutable reference, the contents
+    // could change, but not the location.
+    println!("{:?}", foo)
+}
+
+pub fn test2() {
+    let foo: &Box<bool>;
+}
+
+struct Test3<'a> {
+    foo: &'a Box<bool>,
+}
+
+trait Test4 {
+    fn test4(a: &Box<bool>);
+}
+
+impl<'a> Test4 for Test3<'a> {
+    fn test4(a: &Box<bool>) {
+        unimplemented!();
+    }
+}
+
+use std::any::Any;
+
+pub fn test5(foo: &mut Box<dyn Any>) {
+    println!("{:?}", foo)
+}
+
+pub fn test6() {
+    let foo: &Box<dyn Any>;
+}
+
+struct Test7<'a> {
+    foo: &'a Box<dyn Any>,
+}
+
+trait Test8 {
+    fn test8(a: &Box<dyn Any>);
+}
+
+impl<'a> Test8 for Test7<'a> {
+    fn test8(a: &Box<dyn Any>) {
+        unimplemented!();
+    }
+}
+
+pub fn test9(foo: &mut Box<dyn Any + Send + Sync>) {
+    let _ = foo;
+}
+
+pub fn test10() {
+    let foo: &Box<dyn Any + Send + 'static>;
+}
+
+struct Test11<'a> {
+    foo: &'a Box<dyn Any + Send>,
+}
+
+trait Test12 {
+    fn test4(a: &Box<dyn Any + 'static>);
+}
+
+impl<'a> Test12 for Test11<'a> {
+    fn test4(a: &Box<dyn Any + 'static>) {
+        unimplemented!();
+    }
+}
+
+pub fn test13(boxed_slice: &mut Box<[i32]>) {
+    // Unconditionally replaces the box pointer.
+    //
+    // This cannot be accomplished if "&mut [i32]" is passed,
+    // and provides a test case where passing a reference to
+    // a Box is valid.
+    let mut data = vec![12];
+    *boxed_slice = data.into_boxed_slice();
+}
+
+fn main() {
+    test1(&mut Box::new(false));
+    test2();
+    test5(&mut (Box::new(false) as Box<dyn Any>));
+    test6();
+    test9(&mut (Box::new(false) as Box<dyn Any + Send + Sync>));
+    test10();
+}
diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr
new file mode 100644
index 00000000000..b5db691f89f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_box.stderr
@@ -0,0 +1,26 @@
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:19:14
+   |
+LL |     let foo: &Box<bool>;
+   |              ^^^^^^^^^^ help: try: `&bool`
+   |
+note: the lint level is defined here
+  --> $DIR/borrow_box.rs:1:9
+   |
+LL | #![deny(clippy::borrowed_box)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:23:10
+   |
+LL |     foo: &'a Box<bool>,
+   |          ^^^^^^^^^^^^^ help: try: `&'a bool`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:27:17
+   |
+LL |     fn test4(a: &Box<bool>);
+   |                 ^^^^^^^^^^ help: try: `&bool`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
new file mode 100644
index 00000000000..fef9f4f39f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
@@ -0,0 +1,85 @@
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::fmt::Display;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Once;
+
+const ATOMIC: AtomicUsize = AtomicUsize::new(5);
+const CELL: Cell<usize> = Cell::new(6);
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+const INTEGER: u8 = 8;
+const STRING: String = String::new();
+const STR: &str = "012345";
+const COW: Cow<str> = Cow::Borrowed("abcdef");
+const NO_ANN: &dyn Display = &70;
+static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
+const ONCE_INIT: Once = Once::new();
+
+trait Trait<T>: Copy {
+    type NonCopyType;
+
+    const ATOMIC: AtomicUsize;
+}
+
+impl Trait<u32> for u64 {
+    type NonCopyType = u16;
+
+    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+}
+
+fn main() {
+    ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
+    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
+
+    let _once = ONCE_INIT;
+    let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
+    let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
+    let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
+    let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
+    let _atomic_into_inner = ATOMIC.into_inner();
+    // these should be all fine.
+    let _twice = (ONCE_INIT, ONCE_INIT);
+    let _ref_twice = &(ONCE_INIT, ONCE_INIT);
+    let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
+    let _array_twice = [ONCE_INIT, ONCE_INIT];
+    let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
+    let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
+
+    // referencing projection is still bad.
+    let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
+    let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
+    let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
+    let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
+    let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability
+    let _ = &ATOMIC_TUPLE.2;
+    let _ = (&&&&ATOMIC_TUPLE).0;
+    let _ = (&&&&ATOMIC_TUPLE).2;
+    let _ = ATOMIC_TUPLE.0;
+    let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+    let _ = ATOMIC_TUPLE.1.into_iter();
+    let _ = ATOMIC_TUPLE.2;
+    let _ = &{ ATOMIC_TUPLE };
+
+    CELL.set(2); //~ ERROR interior mutability
+    assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
+
+    assert_eq!(INTEGER, 8);
+    assert!(STRING.is_empty());
+
+    let a = ATOMIC;
+    a.store(4, Ordering::SeqCst);
+    assert_eq!(a.load(Ordering::SeqCst), 4);
+
+    STATIC_TUPLE.0.store(3, Ordering::SeqCst);
+    assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
+    assert!(STATIC_TUPLE.1.is_empty());
+
+    u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
+    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
+
+    assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
+}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
new file mode 100644
index 00000000000..dc738064a17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
@@ -0,0 +1,131 @@
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:34:5
+   |
+LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
+   |     ^^^^^^
+   |
+   = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:35:16
+   |
+LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
+   |                ^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:38:22
+   |
+LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
+   |                      ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:39:25
+   |
+LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
+   |                         ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:40:27
+   |
+LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
+   |                           ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:41:26
+   |
+LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
+   |                          ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:52:14
+   |
+LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:53:14
+   |
+LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:54:19
+   |
+LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
+   |                   ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:55:14
+   |
+LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:56:13
+   |
+LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
+   |             ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:62:13
+   |
+LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+   |             ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:67:5
+   |
+LL |     CELL.set(2); //~ ERROR interior mutability
+   |     ^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:68:16
+   |
+LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
+   |                ^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:81:5
+   |
+LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
+   |     ^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:82:16
+   |
+LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
+   |                ^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/box_vec.rs b/src/tools/clippy/tests/ui/box_vec.rs
new file mode 100644
index 00000000000..87b67c23704
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_vec.rs
@@ -0,0 +1,32 @@
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name)]
+
+macro_rules! boxit {
+    ($init:expr, $x:ty) => {
+        let _: Box<$x> = Box::new($init);
+    };
+}
+
+fn test_macro() {
+    boxit!(Vec::new(), Vec<u8>);
+}
+pub fn test(foo: Box<Vec<bool>>) {
+    println!("{:?}", foo.get(0))
+}
+
+pub fn test2(foo: Box<dyn Fn(Vec<u32>)>) {
+    // pass if #31 is fixed
+    foo(vec![1, 2, 3])
+}
+
+pub fn test_local_not_linted() {
+    let _: Box<Vec<bool>>;
+}
+
+fn main() {
+    test(Box::new(Vec::new()));
+    test2(Box::new(|v| println!("{:?}", v)));
+    test_macro();
+    test_local_not_linted();
+}
diff --git a/src/tools/clippy/tests/ui/box_vec.stderr b/src/tools/clippy/tests/ui/box_vec.stderr
new file mode 100644
index 00000000000..fca12eddd57
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_vec.stderr
@@ -0,0 +1,11 @@
+error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
+  --> $DIR/box_vec.rs:14:18
+   |
+LL | pub fn test(foo: Box<Vec<bool>>) {
+   |                  ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::box-vec` implied by `-D warnings`
+   = help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/builtin-type-shadow.rs b/src/tools/clippy/tests/ui/builtin-type-shadow.rs
new file mode 100644
index 00000000000..69b8b6a0e68
--- /dev/null
+++ b/src/tools/clippy/tests/ui/builtin-type-shadow.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::builtin_type_shadow)]
+#![allow(non_camel_case_types)]
+
+fn foo<u32>(a: u32) -> u32 {
+    42
+    // ^ rustc's type error
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/builtin-type-shadow.stderr b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
new file mode 100644
index 00000000000..b6a4adde848
--- /dev/null
+++ b/src/tools/clippy/tests/ui/builtin-type-shadow.stderr
@@ -0,0 +1,26 @@
+error: This generic shadows the built-in type `u32`
+  --> $DIR/builtin-type-shadow.rs:4:8
+   |
+LL | fn foo<u32>(a: u32) -> u32 {
+   |        ^^^
+   |
+   = note: `-D clippy::builtin-type-shadow` implied by `-D warnings`
+
+error[E0308]: mismatched types
+  --> $DIR/builtin-type-shadow.rs:5:5
+   |
+LL | fn foo<u32>(a: u32) -> u32 {
+   |        ---             --- expected `u32` because of return type
+   |        |
+   |        this type parameter
+LL |     42
+   |     ^^ expected type parameter `u32`, found integer
+   |
+   = note: expected type parameter `u32`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/clippy/tests/ui/bytecount.rs b/src/tools/clippy/tests/ui/bytecount.rs
new file mode 100644
index 00000000000..c724ee21be3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bytecount.rs
@@ -0,0 +1,24 @@
+#[deny(clippy::naive_bytecount)]
+fn main() {
+    let x = vec![0_u8; 16];
+
+    let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
+
+    let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
+
+    let _ = x.iter().filter(|a| **a > 0).count(); // not an equality count, OK.
+
+    let _ = x.iter().map(|a| a + 1).filter(|&a| a < 15).count(); // not a slice
+
+    let b = 0;
+
+    let _ = x.iter().filter(|_| b > 0).count(); // woah there
+
+    let _ = x.iter().filter(|_a| b == b + 1).count(); // nothing to see here, move along
+
+    let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
+
+    let y = vec![0_u16; 3];
+
+    let _ = y.iter().filter(|&&a| a == 0).count(); // naive count, but not bytes
+}
diff --git a/src/tools/clippy/tests/ui/bytecount.stderr b/src/tools/clippy/tests/ui/bytecount.stderr
new file mode 100644
index 00000000000..436f5d86a06
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bytecount.stderr
@@ -0,0 +1,26 @@
+error: You appear to be counting bytes the naive way
+  --> $DIR/bytecount.rs:5:13
+   |
+LL |     let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)`
+   |
+note: the lint level is defined here
+  --> $DIR/bytecount.rs:1:8
+   |
+LL | #[deny(clippy::naive_bytecount)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: You appear to be counting bytes the naive way
+  --> $DIR/bytecount.rs:7:13
+   |
+LL |     let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
+
+error: You appear to be counting bytes the naive way
+  --> $DIR/bytecount.rs:19:13
+   |
+LL |     let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
new file mode 100644
index 00000000000..7e0b211d862
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -0,0 +1,95 @@
+#[warn(
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation,
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap
+)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+fn main() {
+    // Test clippy::cast_precision_loss
+    let x0 = 1i32;
+    x0 as f32;
+    let x1 = 1i64;
+    x1 as f32;
+    x1 as f64;
+    let x2 = 1u32;
+    x2 as f32;
+    let x3 = 1u64;
+    x3 as f32;
+    x3 as f64;
+    // Test clippy::cast_possible_truncation
+    1f32 as i32;
+    1f32 as u32;
+    1f64 as f32;
+    1i32 as i8;
+    1i32 as u8;
+    1f64 as isize;
+    1f64 as usize;
+    // Test clippy::cast_possible_wrap
+    1u8 as i8;
+    1u16 as i16;
+    1u32 as i32;
+    1u64 as i64;
+    1usize as isize;
+    // Test clippy::cast_sign_loss
+    1i32 as u32;
+    -1i32 as u32;
+    1isize as usize;
+    -1isize as usize;
+    0i8 as u8;
+    i8::max_value() as u8;
+    i16::max_value() as u16;
+    i32::max_value() as u32;
+    i64::max_value() as u64;
+    i128::max_value() as u128;
+
+    (-1i8).abs() as u8;
+    (-1i16).abs() as u16;
+    (-1i32).abs() as u32;
+    (-1i64).abs() as u64;
+    (-1isize).abs() as usize;
+
+    (-1i8).checked_abs().unwrap() as u8;
+    (-1i16).checked_abs().unwrap() as u16;
+    (-1i32).checked_abs().unwrap() as u32;
+    (-1i64).checked_abs().unwrap() as u64;
+    (-1isize).checked_abs().unwrap() as usize;
+
+    (-1i8).rem_euclid(1i8) as u8;
+    (-1i8).rem_euclid(1i8) as u16;
+    (-1i16).rem_euclid(1i16) as u16;
+    (-1i16).rem_euclid(1i16) as u32;
+    (-1i32).rem_euclid(1i32) as u32;
+    (-1i32).rem_euclid(1i32) as u64;
+    (-1i64).rem_euclid(1i64) as u64;
+    (-1i64).rem_euclid(1i64) as u128;
+    (-1isize).rem_euclid(1isize) as usize;
+    (1i8).rem_euclid(-1i8) as u8;
+    (1i8).rem_euclid(-1i8) as u16;
+    (1i16).rem_euclid(-1i16) as u16;
+    (1i16).rem_euclid(-1i16) as u32;
+    (1i32).rem_euclid(-1i32) as u32;
+    (1i32).rem_euclid(-1i32) as u64;
+    (1i64).rem_euclid(-1i64) as u64;
+    (1i64).rem_euclid(-1i64) as u128;
+    (1isize).rem_euclid(-1isize) as usize;
+
+    (-1i8).checked_rem_euclid(1i8).unwrap() as u8;
+    (-1i8).checked_rem_euclid(1i8).unwrap() as u16;
+    (-1i16).checked_rem_euclid(1i16).unwrap() as u16;
+    (-1i16).checked_rem_euclid(1i16).unwrap() as u32;
+    (-1i32).checked_rem_euclid(1i32).unwrap() as u32;
+    (-1i32).checked_rem_euclid(1i32).unwrap() as u64;
+    (-1i64).checked_rem_euclid(1i64).unwrap() as u64;
+    (-1i64).checked_rem_euclid(1i64).unwrap() as u128;
+    (-1isize).checked_rem_euclid(1isize).unwrap() as usize;
+    (1i8).checked_rem_euclid(-1i8).unwrap() as u8;
+    (1i8).checked_rem_euclid(-1i8).unwrap() as u16;
+    (1i16).checked_rem_euclid(-1i16).unwrap() as u16;
+    (1i16).checked_rem_euclid(-1i16).unwrap() as u32;
+    (1i32).checked_rem_euclid(-1i32).unwrap() as u32;
+    (1i32).checked_rem_euclid(-1i32).unwrap() as u64;
+    (1i64).checked_rem_euclid(-1i64).unwrap() as u64;
+    (1i64).checked_rem_euclid(-1i64).unwrap() as u128;
+    (1isize).checked_rem_euclid(-1isize).unwrap() as usize;
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
new file mode 100644
index 00000000000..4c66d736494
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -0,0 +1,142 @@
+error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast.rs:11:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
+
+error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast.rs:13:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^
+
+error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast.rs:14:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^
+
+error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast.rs:16:5
+   |
+LL |     x2 as f32;
+   |     ^^^^^^^^^
+
+error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast.rs:18:5
+   |
+LL |     x3 as f32;
+   |     ^^^^^^^^^
+
+error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast.rs:19:5
+   |
+LL |     x3 as f64;
+   |     ^^^^^^^^^
+
+error: casting `f32` to `i32` may truncate the value
+  --> $DIR/cast.rs:21:5
+   |
+LL |     1f32 as i32;
+   |     ^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+
+error: casting `f32` to `u32` may truncate the value
+  --> $DIR/cast.rs:22:5
+   |
+LL |     1f32 as u32;
+   |     ^^^^^^^^^^^
+
+error: casting `f32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:22:5
+   |
+LL |     1f32 as u32;
+   |     ^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-sign-loss` implied by `-D warnings`
+
+error: casting `f64` to `f32` may truncate the value
+  --> $DIR/cast.rs:23:5
+   |
+LL |     1f64 as f32;
+   |     ^^^^^^^^^^^
+
+error: casting `i32` to `i8` may truncate the value
+  --> $DIR/cast.rs:24:5
+   |
+LL |     1i32 as i8;
+   |     ^^^^^^^^^^
+
+error: casting `i32` to `u8` may truncate the value
+  --> $DIR/cast.rs:25:5
+   |
+LL |     1i32 as u8;
+   |     ^^^^^^^^^^
+
+error: casting `f64` to `isize` may truncate the value
+  --> $DIR/cast.rs:26:5
+   |
+LL |     1f64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `f64` to `usize` may truncate the value
+  --> $DIR/cast.rs:27:5
+   |
+LL |     1f64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `f64` to `usize` may lose the sign of the value
+  --> $DIR/cast.rs:27:5
+   |
+LL |     1f64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u8` to `i8` may wrap around the value
+  --> $DIR/cast.rs:29:5
+   |
+LL |     1u8 as i8;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
+
+error: casting `u16` to `i16` may wrap around the value
+  --> $DIR/cast.rs:30:5
+   |
+LL |     1u16 as i16;
+   |     ^^^^^^^^^^^
+
+error: casting `u32` to `i32` may wrap around the value
+  --> $DIR/cast.rs:31:5
+   |
+LL |     1u32 as i32;
+   |     ^^^^^^^^^^^
+
+error: casting `u64` to `i64` may wrap around the value
+  --> $DIR/cast.rs:32:5
+   |
+LL |     1u64 as i64;
+   |     ^^^^^^^^^^^
+
+error: casting `usize` to `isize` may wrap around the value
+  --> $DIR/cast.rs:33:5
+   |
+LL |     1usize as isize;
+   |     ^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:36:5
+   |
+LL |     -1i32 as u32;
+   |     ^^^^^^^^^^^^
+
+error: casting `isize` to `usize` may lose the sign of the value
+  --> $DIR/cast.rs:38:5
+   |
+LL |     -1isize as usize;
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 22 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_alignment.rs b/src/tools/clippy/tests/ui/cast_alignment.rs
new file mode 100644
index 00000000000..4c08935639f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_alignment.rs
@@ -0,0 +1,27 @@
+//! Test casts for alignment issues
+
+#![feature(rustc_private)]
+extern crate libc;
+
+#[warn(clippy::cast_ptr_alignment)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
+fn main() {
+    /* These should be warned against */
+
+    // cast to more-strictly-aligned type
+    (&1u8 as *const u8) as *const u16;
+    (&mut 1u8 as *mut u8) as *mut u16;
+
+    /* These should be ok */
+
+    // not a pointer type
+    1u8 as u16;
+    // cast to less-strictly-aligned type
+    (&1u16 as *const u16) as *const u8;
+    (&mut 1u16 as *mut u16) as *mut u8;
+    // For c_void, we should trust the user. See #2677
+    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
+    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
+    // For ZST, we should trust the user. See #4256
+    (&1u32 as *const u32 as *const ()) as *const u32;
+}
diff --git a/src/tools/clippy/tests/ui/cast_alignment.stderr b/src/tools/clippy/tests/ui/cast_alignment.stderr
new file mode 100644
index 00000000000..79219f86155
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_alignment.stderr
@@ -0,0 +1,16 @@
+error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
+  --> $DIR/cast_alignment.rs:12:5
+   |
+LL |     (&1u8 as *const u8) as *const u16;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings`
+
+error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
+  --> $DIR/cast_alignment.rs:13:5
+   |
+LL |     (&mut 1u8 as *mut u8) as *mut u16;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
new file mode 100644
index 00000000000..709d58b596c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to floating-point types
+    let x0 = 1i8;
+    f32::from(x0);
+    f64::from(x0);
+    let x1 = 1u8;
+    f32::from(x1);
+    f64::from(x1);
+    let x2 = 1i16;
+    f32::from(x2);
+    f64::from(x2);
+    let x3 = 1u16;
+    f32::from(x3);
+    f64::from(x3);
+    let x4 = 1i32;
+    f64::from(x4);
+    let x5 = 1u32;
+    f64::from(x5);
+
+    // Test with casts from floating-point types
+    f64::from(1.0f32);
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: f32) -> f64 {
+    input as f64
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+    struct A;
+
+    impl A {
+        pub const fn convert(x: f32) -> f64 {
+            x as f64
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs
new file mode 100644
index 00000000000..eb0aab88642
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to floating-point types
+    let x0 = 1i8;
+    x0 as f32;
+    x0 as f64;
+    let x1 = 1u8;
+    x1 as f32;
+    x1 as f64;
+    let x2 = 1i16;
+    x2 as f32;
+    x2 as f64;
+    let x3 = 1u16;
+    x3 as f32;
+    x3 as f64;
+    let x4 = 1i32;
+    x4 as f64;
+    let x5 = 1u32;
+    x5 as f64;
+
+    // Test with casts from floating-point types
+    1.0f32 as f64;
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: f32) -> f64 {
+    input as f64
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+    struct A;
+
+    impl A {
+        pub const fn convert(x: f32) -> f64 {
+            x as f64
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
new file mode 100644
index 00000000000..0ed09f3083c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
@@ -0,0 +1,70 @@
+error: casting `i8` to `f32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:9:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x0)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: casting `i8` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:10:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x0)`
+
+error: casting `u8` to `f32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:12:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x1)`
+
+error: casting `u8` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:13:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x1)`
+
+error: casting `i16` to `f32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:15:5
+   |
+LL |     x2 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x2)`
+
+error: casting `i16` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:16:5
+   |
+LL |     x2 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x2)`
+
+error: casting `u16` to `f32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:18:5
+   |
+LL |     x3 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x3)`
+
+error: casting `u16` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:19:5
+   |
+LL |     x3 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x3)`
+
+error: casting `i32` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:21:5
+   |
+LL |     x4 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x4)`
+
+error: casting `u32` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:23:5
+   |
+LL |     x5 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x5)`
+
+error: casting `f32` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:26:5
+   |
+LL |     1.0f32 as f64;
+   |     ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
new file mode 100644
index 00000000000..03e49adb117
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
@@ -0,0 +1,47 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to integer types
+    i16::from(1i8);
+    i32::from(1i8);
+    i64::from(1i8);
+    i16::from(1u8);
+    i32::from(1u8);
+    i64::from(1u8);
+    u16::from(1u8);
+    u32::from(1u8);
+    u64::from(1u8);
+    i32::from(1i16);
+    i64::from(1i16);
+    i32::from(1u16);
+    i64::from(1u16);
+    u32::from(1u16);
+    u64::from(1u16);
+    i64::from(1i32);
+    i64::from(1u32);
+    u64::from(1u32);
+
+    // Test with an expression wrapped in parens
+    u16::from(1u8 + 1u8);
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: u16) -> u32 {
+    input as u32
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+    struct A;
+
+    impl A {
+        pub const fn convert(x: u32) -> u64 {
+            x as u64
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.rs b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
new file mode 100644
index 00000000000..6a984d24596
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
@@ -0,0 +1,47 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to integer types
+    1i8 as i16;
+    1i8 as i32;
+    1i8 as i64;
+    1u8 as i16;
+    1u8 as i32;
+    1u8 as i64;
+    1u8 as u16;
+    1u8 as u32;
+    1u8 as u64;
+    1i16 as i32;
+    1i16 as i64;
+    1u16 as i32;
+    1u16 as i64;
+    1u16 as u32;
+    1u16 as u64;
+    1i32 as i64;
+    1u32 as i64;
+    1u32 as u64;
+
+    // Test with an expression wrapped in parens
+    (1u8 + 1u8) as u16;
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: u16) -> u32 {
+    input as u32
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+    struct A;
+
+    impl A {
+        pub const fn convert(x: u32) -> u64 {
+            x as u64
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr
new file mode 100644
index 00000000000..8e2890f9c28
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr
@@ -0,0 +1,118 @@
+error: casting `i8` to `i16` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:8:5
+   |
+LL |     1i8 as i16;
+   |     ^^^^^^^^^^ help: try: `i16::from(1i8)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: casting `i8` to `i32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:9:5
+   |
+LL |     1i8 as i32;
+   |     ^^^^^^^^^^ help: try: `i32::from(1i8)`
+
+error: casting `i8` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:10:5
+   |
+LL |     1i8 as i64;
+   |     ^^^^^^^^^^ help: try: `i64::from(1i8)`
+
+error: casting `u8` to `i16` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:11:5
+   |
+LL |     1u8 as i16;
+   |     ^^^^^^^^^^ help: try: `i16::from(1u8)`
+
+error: casting `u8` to `i32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:12:5
+   |
+LL |     1u8 as i32;
+   |     ^^^^^^^^^^ help: try: `i32::from(1u8)`
+
+error: casting `u8` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:13:5
+   |
+LL |     1u8 as i64;
+   |     ^^^^^^^^^^ help: try: `i64::from(1u8)`
+
+error: casting `u8` to `u16` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:14:5
+   |
+LL |     1u8 as u16;
+   |     ^^^^^^^^^^ help: try: `u16::from(1u8)`
+
+error: casting `u8` to `u32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:15:5
+   |
+LL |     1u8 as u32;
+   |     ^^^^^^^^^^ help: try: `u32::from(1u8)`
+
+error: casting `u8` to `u64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:16:5
+   |
+LL |     1u8 as u64;
+   |     ^^^^^^^^^^ help: try: `u64::from(1u8)`
+
+error: casting `i16` to `i32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:17:5
+   |
+LL |     1i16 as i32;
+   |     ^^^^^^^^^^^ help: try: `i32::from(1i16)`
+
+error: casting `i16` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:18:5
+   |
+LL |     1i16 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1i16)`
+
+error: casting `u16` to `i32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:19:5
+   |
+LL |     1u16 as i32;
+   |     ^^^^^^^^^^^ help: try: `i32::from(1u16)`
+
+error: casting `u16` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:20:5
+   |
+LL |     1u16 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1u16)`
+
+error: casting `u16` to `u32` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:21:5
+   |
+LL |     1u16 as u32;
+   |     ^^^^^^^^^^^ help: try: `u32::from(1u16)`
+
+error: casting `u16` to `u64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:22:5
+   |
+LL |     1u16 as u64;
+   |     ^^^^^^^^^^^ help: try: `u64::from(1u16)`
+
+error: casting `i32` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:23:5
+   |
+LL |     1i32 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1i32)`
+
+error: casting `u32` to `i64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:24:5
+   |
+LL |     1u32 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1u32)`
+
+error: casting `u32` to `u64` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:25:5
+   |
+LL |     1u32 as u64;
+   |     ^^^^^^^^^^^ help: try: `u64::from(1u32)`
+
+error: casting `u8` to `u16` may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:28:5
+   |
+LL |     (1u8 + 1u8) as u16;
+   |     ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`
+
+error: aborting due to 19 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_ref_to_mut.rs b/src/tools/clippy/tests/ui/cast_ref_to_mut.rs
new file mode 100644
index 00000000000..089e5cfabe4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_ref_to_mut.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::cast_ref_to_mut)]
+#![allow(clippy::no_effect)]
+
+extern "C" {
+    // N.B., mutability can be easily incorrect in FFI calls -- as
+    // in C, the default is mutable pointers.
+    fn ffi(c: *mut u8);
+    fn int_ffi(c: *mut i32);
+}
+
+fn main() {
+    let s = String::from("Hello");
+    let a = &s;
+    unsafe {
+        let num = &3i32;
+        let mut_num = &mut 3i32;
+        // Should be warned against
+        (*(a as *const _ as *mut String)).push_str(" world");
+        *(a as *const _ as *mut _) = String::from("Replaced");
+        *(a as *const _ as *mut String) += " world";
+        // Shouldn't be warned against
+        println!("{}", *(num as *const _ as *const i16));
+        println!("{}", *(mut_num as *mut _ as *mut i16));
+        ffi(a.as_ptr() as *mut _);
+        int_ffi(num as *const _ as *mut _);
+        int_ffi(&3 as *const _ as *mut _);
+        let mut value = 3;
+        let value: *const i32 = &mut value;
+        *(value as *const i16 as *mut i16) = 42;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_ref_to_mut.stderr b/src/tools/clippy/tests/ui/cast_ref_to_mut.stderr
new file mode 100644
index 00000000000..aacd99437d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_ref_to_mut.stderr
@@ -0,0 +1,22 @@
+error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`
+  --> $DIR/cast_ref_to_mut.rs:18:9
+   |
+LL |         (*(a as *const _ as *mut String)).push_str(" world");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-ref-to-mut` implied by `-D warnings`
+
+error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`
+  --> $DIR/cast_ref_to_mut.rs:19:9
+   |
+LL |         *(a as *const _ as *mut _) = String::from("Replaced");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`
+  --> $DIR/cast_ref_to_mut.rs:20:9
+   |
+LL |         *(a as *const _ as *mut String) += " world";
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs
new file mode 100644
index 00000000000..595109be46b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_size.rs
@@ -0,0 +1,35 @@
+// ignore-32bit
+#[warn(
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation,
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap,
+    clippy::cast_lossless
+)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+fn main() {
+    // Casting from *size
+    1isize as i8;
+    let x0 = 1isize;
+    let x1 = 1usize;
+    x0 as f64;
+    x1 as f64;
+    x0 as f32;
+    x1 as f32;
+    1isize as i32;
+    1isize as u32;
+    1usize as u32;
+    1usize as i32;
+    // Casting to *size
+    1i64 as isize;
+    1i64 as usize;
+    1u64 as isize;
+    1u64 as usize;
+    1u32 as isize;
+    1u32 as usize; // Should not trigger any lint
+    1i32 as isize; // Neither should this
+    1i32 as usize;
+    // Big integer literal to float
+    999_999_999 as f32;
+    9_999_999_999_999_999usize as f64;
+}
diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.stderr
new file mode 100644
index 00000000000..95552f2e285
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_size.stderr
@@ -0,0 +1,116 @@
+error: casting `isize` to `i8` may truncate the value
+  --> $DIR/cast_size.rs:12:5
+   |
+LL |     1isize as i8;
+   |     ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+
+error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size.rs:15:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
+
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size.rs:16:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^
+
+error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size.rs:17:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^
+
+error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size.rs:18:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^
+
+error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:19:5
+   |
+LL |     1isize as i32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:20:5
+   |
+LL |     1isize as u32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:21:5
+   |
+LL |     1usize as u32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:22:5
+   |
+LL |     1usize as i32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:22:5
+   |
+LL |     1usize as i32;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
+
+error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:24:5
+   |
+LL |     1i64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:25:5
+   |
+LL |     1i64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:26:5
+   |
+LL |     1u64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:26:5
+   |
+LL |     1u64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:27:5
+   |
+LL |     1u64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size.rs:28:5
+   |
+LL |     1u32 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size.rs:33:5
+   |
+LL |     999_999_999 as f32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size.rs:34:5
+   |
+LL |     9_999_999_999_999_999usize as f64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.rs b/src/tools/clippy/tests/ui/cast_size_32bit.rs
new file mode 100644
index 00000000000..99aac6deca3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_size_32bit.rs
@@ -0,0 +1,35 @@
+// ignore-64bit
+#[warn(
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation,
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap,
+    clippy::cast_lossless
+)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+fn main() {
+    // Casting from *size
+    1isize as i8;
+    let x0 = 1isize;
+    let x1 = 1usize;
+    x0 as f64;
+    x1 as f64;
+    x0 as f32;
+    x1 as f32;
+    1isize as i32;
+    1isize as u32;
+    1usize as u32;
+    1usize as i32;
+    // Casting to *size
+    1i64 as isize;
+    1i64 as usize;
+    1u64 as isize;
+    1u64 as usize;
+    1u32 as isize;
+    1u32 as usize; // Should not trigger any lint
+    1i32 as isize; // Neither should this
+    1i32 as usize;
+    // Big integer literal to float
+    999_999_999 as f32;
+    3_999_999_999usize as f64;
+}
diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.stderr b/src/tools/clippy/tests/ui/cast_size_32bit.stderr
new file mode 100644
index 00000000000..2eec51895f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_size_32bit.stderr
@@ -0,0 +1,132 @@
+error: casting `isize` to `i8` may truncate the value
+  --> $DIR/cast_size_32bit.rs:12:5
+   |
+LL |     1isize as i8;
+   |     ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+
+error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size_32bit.rs:15:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
+
+error: casting `isize` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_size_32bit.rs:15:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x0)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> $DIR/cast_size_32bit.rs:16:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^
+
+error: casting `usize` to `f64` may become silently lossy if you later change the type
+  --> $DIR/cast_size_32bit.rs:16:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x1)`
+
+error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size_32bit.rs:17:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^
+
+error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size_32bit.rs:18:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^
+
+error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:19:5
+   |
+LL |     1isize as i32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:20:5
+   |
+LL |     1isize as u32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:21:5
+   |
+LL |     1usize as u32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:22:5
+   |
+LL |     1usize as i32;
+   |     ^^^^^^^^^^^^^
+
+error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:22:5
+   |
+LL |     1usize as i32;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
+
+error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:24:5
+   |
+LL |     1i64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:25:5
+   |
+LL |     1i64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:26:5
+   |
+LL |     1u64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:26:5
+   |
+LL |     1u64 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:27:5
+   |
+LL |     1u64 as usize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
+  --> $DIR/cast_size_32bit.rs:28:5
+   |
+LL |     1u32 as isize;
+   |     ^^^^^^^^^^^^^
+
+error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> $DIR/cast_size_32bit.rs:33:5
+   |
+LL |     999_999_999 as f32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/cast_size_32bit.rs:34:5
+   |
+LL |     3_999_999_999usize as f64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `3999999999_f64`
+   |
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
new file mode 100644
index 00000000000..4e583a25b94
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+
+#![allow(unused, clippy::no_effect)]
+#![warn(clippy::deprecated_cfg_attr)]
+
+// This doesn't get linted, see known problems
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#[rustfmt::skip]
+trait Foo
+{
+fn foo(
+);
+}
+
+fn skip_on_statements() {
+    #[rustfmt::skip]
+    5+3;
+}
+
+#[rustfmt::skip]
+fn main() {
+    foo::f();
+}
+
+mod foo {
+    #![cfg_attr(rustfmt, rustfmt_skip)]
+
+    pub fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
new file mode 100644
index 00000000000..9c0fcf6fb45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+
+#![allow(unused, clippy::no_effect)]
+#![warn(clippy::deprecated_cfg_attr)]
+
+// This doesn't get linted, see known problems
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#[rustfmt::skip]
+trait Foo
+{
+fn foo(
+);
+}
+
+fn skip_on_statements() {
+    #[cfg_attr(rustfmt, rustfmt::skip)]
+    5+3;
+}
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn main() {
+    foo::f();
+}
+
+mod foo {
+    #![cfg_attr(rustfmt, rustfmt_skip)]
+
+    pub fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
new file mode 100644
index 00000000000..c1efd47db90
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
@@ -0,0 +1,16 @@
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
+  --> $DIR/cfg_attr_rustfmt.rs:18:5
+   |
+LL |     #[cfg_attr(rustfmt, rustfmt::skip)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+   |
+   = note: `-D clippy::deprecated-cfg-attr` implied by `-D warnings`
+
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
+  --> $DIR/cfg_attr_rustfmt.rs:22:1
+   |
+LL | #[cfg_attr(rustfmt, rustfmt_skip)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.rs b/src/tools/clippy/tests/ui/char_lit_as_u8.rs
new file mode 100644
index 00000000000..0a53a3d6490
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::char_lit_as_u8)]
+
+fn main() {
+    let _ = '❤' as u8; // no suggestion, since a byte literal won't work.
+}
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
new file mode 100644
index 00000000000..b9836d2f255
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
@@ -0,0 +1,11 @@
+error: casting a character literal to `u8` truncates
+  --> $DIR/char_lit_as_u8.rs:4:13
+   |
+LL |     let _ = '❤' as u8; // no suggestion, since a byte literal won't work.
+   |             ^^^^^^^^^
+   |
+   = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed
new file mode 100644
index 00000000000..3dc3cb4e757
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#![warn(clippy::char_lit_as_u8)]
+
+fn main() {
+    let _ = b'a';
+    let _ = b'\n';
+    let _ = b'\0';
+    let _ = b'\x01';
+}
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs
new file mode 100644
index 00000000000..d379a023494
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#![warn(clippy::char_lit_as_u8)]
+
+fn main() {
+    let _ = 'a' as u8;
+    let _ = '\n' as u8;
+    let _ = '\0' as u8;
+    let _ = '\x01' as u8;
+}
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
new file mode 100644
index 00000000000..bf7cb1607b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
@@ -0,0 +1,35 @@
+error: casting a character literal to `u8` truncates
+  --> $DIR/char_lit_as_u8_suggestions.rs:6:13
+   |
+LL |     let _ = 'a' as u8;
+   |             ^^^^^^^^^ help: use a byte literal instead: `b'a'`
+   |
+   = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: casting a character literal to `u8` truncates
+  --> $DIR/char_lit_as_u8_suggestions.rs:7:13
+   |
+LL |     let _ = '/n' as u8;
+   |             ^^^^^^^^^^ help: use a byte literal instead: `b'/n'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: casting a character literal to `u8` truncates
+  --> $DIR/char_lit_as_u8_suggestions.rs:8:13
+   |
+LL |     let _ = '/0' as u8;
+   |             ^^^^^^^^^^ help: use a byte literal instead: `b'/0'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: casting a character literal to `u8` truncates
+  --> $DIR/char_lit_as_u8_suggestions.rs:9:13
+   |
+LL |     let _ = '/x01' as u8;
+   |             ^^^^^^^^^^^^ help: use a byte literal instead: `b'/x01'`
+   |
+   = note: `char` is four bytes wide, but `u8` is a single byte
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
new file mode 100644
index 00000000000..7febd6f3761
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -0,0 +1,106 @@
+// run-rustfix
+
+#![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
+    }
+}
+
+fn i64_to_u16(value: i64) -> Option<u16> {
+    if u16::try_from(value).is_ok() {
+        Some(value as u16)
+    } else {
+        None
+    }
+}
+
+fn isize_to_u8(value: isize) -> Option<u8> {
+    if u8::try_from(value).is_ok() {
+        Some(value as u8)
+    } else {
+        None
+    }
+}
+
+// Signed to signed
+
+fn i64_to_i32(value: i64) -> Option<i32> {
+    if i32::try_from(value).is_ok() {
+        Some(value as i32)
+    } else {
+        None
+    }
+}
+
+fn i64_to_i16(value: i64) -> Option<i16> {
+    if i16::try_from(value).is_ok() {
+        Some(value as i16)
+    } else {
+        None
+    }
+}
+
+// Unsigned to X
+
+fn u32_to_i32(value: u32) -> Option<i32> {
+    if i32::try_from(value).is_ok() {
+        Some(value as i32)
+    } else {
+        None
+    }
+}
+
+fn usize_to_isize(value: usize) -> isize {
+    if isize::try_from(value).is_ok() && value as i32 == 5 {
+        5
+    } else {
+        1
+    }
+}
+
+fn u32_to_u16(value: u32) -> isize {
+    if u16::try_from(value).is_ok() && value as i32 == 5 {
+        5
+    } else {
+        1
+    }
+}
+
+// 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
+    }
+}
+
+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
+    }
+}
+
+fn i8_to_u8(value: i8) -> Option<u8> {
+    if value >= 0 {
+        Some(value as u8)
+    } else {
+        None
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
new file mode 100644
index 00000000000..a643354e243
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -0,0 +1,106 @@
+// run-rustfix
+
+#![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
+    }
+}
+
+fn i64_to_u16(value: i64) -> Option<u16> {
+    if value <= i64::from(u16::max_value()) && value >= 0 {
+        Some(value as u16)
+    } else {
+        None
+    }
+}
+
+fn isize_to_u8(value: isize) -> Option<u8> {
+    if value <= (u8::max_value() as isize) && value >= 0 {
+        Some(value as u8)
+    } else {
+        None
+    }
+}
+
+// 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
+    }
+}
+
+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
+    }
+}
+
+// Unsigned to X
+
+fn u32_to_i32(value: u32) -> Option<i32> {
+    if value <= i32::max_value() as u32 {
+        Some(value as i32)
+    } else {
+        None
+    }
+}
+
+fn usize_to_isize(value: usize) -> isize {
+    if value <= isize::max_value() as usize && value as i32 == 5 {
+        5
+    } else {
+        1
+    }
+}
+
+fn u32_to_u16(value: u32) -> isize {
+    if value <= u16::max_value() as u32 && value as i32 == 5 {
+        5
+    } else {
+        1
+    }
+}
+
+// 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
+    }
+}
+
+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
+    }
+}
+
+fn i8_to_u8(value: i8) -> Option<u8> {
+    if value >= 0 {
+        Some(value as u8)
+    } else {
+        None
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
new file mode 100644
index 00000000000..f678f009621
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -0,0 +1,52 @@
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:13:8
+   |
+LL |     if 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
+   |
+LL |     if 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:29:8
+   |
+LL |     if 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:39:8
+   |
+LL |     if 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:47:8
+   |
+LL |     if 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:57:8
+   |
+LL |     if value <= i32::max_value() as u32 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:65:8
+   |
+LL |     if 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:73:8
+   |
+LL |     if value <= u16::max_value() as u32 && value as i32 == 5 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stdout b/src/tools/clippy/tests/ui/checked_conversions.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_conversions.stdout
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs
new file mode 100644
index 00000000000..c986c992a07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs
@@ -0,0 +1,54 @@
+#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+#![allow(clippy::if_same_then_else)]
+
+fn test_complex_conditions() {
+    let x: Result<(), ()> = Ok(());
+    let y: Result<(), ()> = Ok(());
+    if x.is_ok() && y.is_err() {
+        x.unwrap(); // unnecessary
+        x.unwrap_err(); // will panic
+        y.unwrap(); // will panic
+        y.unwrap_err(); // unnecessary
+    } else {
+        // not statically determinable whether any of the following will always succeed or always fail:
+        x.unwrap();
+        x.unwrap_err();
+        y.unwrap();
+        y.unwrap_err();
+    }
+
+    if x.is_ok() || y.is_ok() {
+        // not statically determinable whether any of the following will always succeed or always fail:
+        x.unwrap();
+        y.unwrap();
+    } else {
+        x.unwrap(); // will panic
+        x.unwrap_err(); // unnecessary
+        y.unwrap(); // will panic
+        y.unwrap_err(); // unnecessary
+    }
+    let z: Result<(), ()> = Ok(());
+    if x.is_ok() && !(y.is_ok() || z.is_err()) {
+        x.unwrap(); // unnecessary
+        x.unwrap_err(); // will panic
+        y.unwrap(); // will panic
+        y.unwrap_err(); // unnecessary
+        z.unwrap(); // unnecessary
+        z.unwrap_err(); // will panic
+    }
+    if x.is_ok() || !(y.is_ok() && z.is_err()) {
+        // not statically determinable whether any of the following will always succeed or always fail:
+        x.unwrap();
+        y.unwrap();
+        z.unwrap();
+    } else {
+        x.unwrap(); // will panic
+        x.unwrap_err(); // unnecessary
+        y.unwrap(); // unnecessary
+        y.unwrap_err(); // will panic
+        z.unwrap(); // will panic
+        z.unwrap_err(); // unnecessary
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
new file mode 100644
index 00000000000..dc666bab460
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
@@ -0,0 +1,192 @@
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:8:9
+   |
+LL |     if x.is_ok() && y.is_err() {
+   |        --------- the check is happening here
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/complex_conditionals.rs:1:35
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/complex_conditionals.rs:9:9
+   |
+LL |     if x.is_ok() && y.is_err() {
+   |        --------- because of this check
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/complex_conditionals.rs:1:9
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:10:9
+   |
+LL |     if x.is_ok() && y.is_err() {
+   |                     ---------- because of this check
+...
+LL |         y.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:11:9
+   |
+LL |     if x.is_ok() && y.is_err() {
+   |                     ---------- the check is happening here
+...
+LL |         y.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:25:9
+   |
+LL |     if x.is_ok() || y.is_ok() {
+   |        --------- because of this check
+...
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:26:9
+   |
+LL |     if x.is_ok() || y.is_ok() {
+   |        --------- the check is happening here
+...
+LL |         x.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:27:9
+   |
+LL |     if x.is_ok() || y.is_ok() {
+   |                     --------- because of this check
+...
+LL |         y.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:28:9
+   |
+LL |     if x.is_ok() || y.is_ok() {
+   |                     --------- the check is happening here
+...
+LL |         y.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:32:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |        --------- the check is happening here
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/complex_conditionals.rs:33:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |        --------- because of this check
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:34:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |                       --------- because of this check
+...
+LL |         y.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:35:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |                       --------- the check is happening here
+...
+LL |         y.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:36:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |                                    ---------- the check is happening here
+...
+LL |         z.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/complex_conditionals.rs:37:9
+   |
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+   |                                    ---------- because of this check
+...
+LL |         z.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:45:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |        --------- because of this check
+...
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:46:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |        --------- the check is happening here
+...
+LL |         x.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:47:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |                       --------- the check is happening here
+...
+LL |         y.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/complex_conditionals.rs:48:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |                       --------- because of this check
+...
+LL |         y.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals.rs:49:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |                                    ---------- because of this check
+...
+LL |         z.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals.rs:50:9
+   |
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+   |                                    ---------- the check is happening here
+...
+LL |         z.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
new file mode 100644
index 00000000000..2307996a48f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
@@ -0,0 +1,15 @@
+#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+#![allow(clippy::if_same_then_else)]
+
+fn test_nested() {
+    fn nested() {
+        let x = Some(());
+        if x.is_some() {
+            x.unwrap(); // unnecessary
+        } else {
+            x.unwrap(); // will panic
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr
new file mode 100644
index 00000000000..e4d085470c3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr
@@ -0,0 +1,31 @@
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/complex_conditionals_nested.rs:8:13
+   |
+LL |         if x.is_some() {
+   |            ----------- the check is happening here
+LL |             x.unwrap(); // unnecessary
+   |             ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/complex_conditionals_nested.rs:1:35
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/complex_conditionals_nested.rs:10:13
+   |
+LL |         if x.is_some() {
+   |            ----------- because of this check
+...
+LL |             x.unwrap(); // will panic
+   |             ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/complex_conditionals_nested.rs:1:9
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
new file mode 100644
index 00000000000..b0fc26ff76d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -0,0 +1,53 @@
+#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+#![allow(clippy::if_same_then_else)]
+
+macro_rules! m {
+    ($a:expr) => {
+        if $a.is_some() {
+            $a.unwrap(); // unnecessary
+        }
+    };
+}
+
+fn main() {
+    let x = Some(());
+    if x.is_some() {
+        x.unwrap(); // unnecessary
+    } else {
+        x.unwrap(); // will panic
+    }
+    if x.is_none() {
+        x.unwrap(); // will panic
+    } else {
+        x.unwrap(); // unnecessary
+    }
+    m!(x);
+    let mut x: Result<(), ()> = Ok(());
+    if x.is_ok() {
+        x.unwrap(); // unnecessary
+        x.unwrap_err(); // will panic
+    } else {
+        x.unwrap(); // will panic
+        x.unwrap_err(); // unnecessary
+    }
+    if x.is_err() {
+        x.unwrap(); // will panic
+        x.unwrap_err(); // unnecessary
+    } else {
+        x.unwrap(); // unnecessary
+        x.unwrap_err(); // will panic
+    }
+    if x.is_ok() {
+        x = Err(());
+        x.unwrap(); // not unnecessary because of mutation of x
+                    // it will always panic but the lint is not smart enough to see this (it only
+                    // checks if conditions).
+    } else {
+        x = Ok(());
+        x.unwrap_err(); // not unnecessary because of mutation of x
+                        // it will always panic but the lint is not smart enough to see this (it
+                        // only checks if conditions).
+    }
+
+    assert!(x.is_ok(), "{:?}", x.unwrap_err()); // ok, it's a common test pattern
+}
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
new file mode 100644
index 00000000000..e40542e2e4f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -0,0 +1,131 @@
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:15:9
+   |
+LL |     if x.is_some() {
+   |        ----------- the check is happening here
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/simple_conditionals.rs:1:35
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/simple_conditionals.rs:17:9
+   |
+LL |     if x.is_some() {
+   |        ----------- because of this check
+...
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/simple_conditionals.rs:1:9
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/simple_conditionals.rs:20:9
+   |
+LL |     if x.is_none() {
+   |        ----------- because of this check
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:22:9
+   |
+LL |     if x.is_none() {
+   |        ----------- the check is happening here
+...
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:7:13
+   |
+LL |         if $a.is_some() {
+   |            ------------ the check is happening here
+LL |             $a.unwrap(); // unnecessary
+   |             ^^^^^^^^^^^
+...
+LL |     m!(x);
+   |     ------ in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:27:9
+   |
+LL |     if x.is_ok() {
+   |        --------- the check is happening here
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/simple_conditionals.rs:28:9
+   |
+LL |     if x.is_ok() {
+   |        --------- because of this check
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/simple_conditionals.rs:30:9
+   |
+LL |     if x.is_ok() {
+   |        --------- because of this check
+...
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:31:9
+   |
+LL |     if x.is_ok() {
+   |        --------- the check is happening here
+...
+LL |         x.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: This call to `unwrap()` will always panic.
+  --> $DIR/simple_conditionals.rs:34:9
+   |
+LL |     if x.is_err() {
+   |        ---------- because of this check
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+
+error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:35:9
+   |
+LL |     if x.is_err() {
+   |        ---------- the check is happening here
+LL |         x.unwrap(); // will panic
+LL |         x.unwrap_err(); // unnecessary
+   |         ^^^^^^^^^^^^^^
+
+error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
+  --> $DIR/simple_conditionals.rs:37:9
+   |
+LL |     if x.is_err() {
+   |        ---------- the check is happening here
+...
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+
+error: This call to `unwrap_err()` will always panic.
+  --> $DIR/simple_conditionals.rs:38:9
+   |
+LL |     if x.is_err() {
+   |        ---------- because of this check
+...
+LL |         x.unwrap_err(); // will panic
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/clone_on_copy_impl.rs b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs
new file mode 100644
index 00000000000..8f9f2a0db8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs
@@ -0,0 +1,22 @@
+use std::fmt;
+use std::marker::PhantomData;
+
+pub struct Key<T> {
+    #[doc(hidden)]
+    pub __name: &'static str,
+    #[doc(hidden)]
+    pub __phantom: PhantomData<T>,
+}
+
+impl<T> Copy for Key<T> {}
+
+impl<T> Clone for Key<T> {
+    fn clone(&self) -> Self {
+        Key {
+            __name: self.__name,
+            __phantom: self.__phantom,
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/clone_on_copy_mut.rs b/src/tools/clippy/tests/ui/clone_on_copy_mut.rs
new file mode 100644
index 00000000000..5bfa256623b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/clone_on_copy_mut.rs
@@ -0,0 +1,18 @@
+pub fn dec_read_dec(i: &mut i32) -> i32 {
+    *i -= 1;
+    let ret = *i;
+    *i -= 1;
+    ret
+}
+
+pub fn minus_1(i: &i32) -> i32 {
+    dec_read_dec(&mut i.clone())
+}
+
+fn main() {
+    let mut i = 10;
+    assert_eq!(minus_1(&i), 9);
+    assert_eq!(i, 10);
+    assert_eq!(dec_read_dec(&mut i), 9);
+    assert_eq!(i, 8);
+}
diff --git a/src/tools/clippy/tests/ui/cmp_nan.rs b/src/tools/clippy/tests/ui/cmp_nan.rs
new file mode 100644
index 00000000000..64ca52b010a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_nan.rs
@@ -0,0 +1,34 @@
+const NAN_F32: f32 = f32::NAN;
+const NAN_F64: f64 = f64::NAN;
+
+#[warn(clippy::cmp_nan)]
+#[allow(clippy::float_cmp, clippy::no_effect, clippy::unnecessary_operation)]
+fn main() {
+    let x = 5f32;
+    x == f32::NAN;
+    x != f32::NAN;
+    x < f32::NAN;
+    x > f32::NAN;
+    x <= f32::NAN;
+    x >= f32::NAN;
+    x == NAN_F32;
+    x != NAN_F32;
+    x < NAN_F32;
+    x > NAN_F32;
+    x <= NAN_F32;
+    x >= NAN_F32;
+
+    let y = 0f64;
+    y == f64::NAN;
+    y != f64::NAN;
+    y < f64::NAN;
+    y > f64::NAN;
+    y <= f64::NAN;
+    y >= f64::NAN;
+    y == NAN_F64;
+    y != NAN_F64;
+    y < NAN_F64;
+    y > NAN_F64;
+    y <= NAN_F64;
+    y >= NAN_F64;
+}
diff --git a/src/tools/clippy/tests/ui/cmp_nan.stderr b/src/tools/clippy/tests/ui/cmp_nan.stderr
new file mode 100644
index 00000000000..867516661a5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_nan.stderr
@@ -0,0 +1,148 @@
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:8:5
+   |
+LL |     x == f32::NAN;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cmp-nan` implied by `-D warnings`
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:9:5
+   |
+LL |     x != f32::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:10:5
+   |
+LL |     x < f32::NAN;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:11:5
+   |
+LL |     x > f32::NAN;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:12:5
+   |
+LL |     x <= f32::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:13:5
+   |
+LL |     x >= f32::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:14:5
+   |
+LL |     x == NAN_F32;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:15:5
+   |
+LL |     x != NAN_F32;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:16:5
+   |
+LL |     x < NAN_F32;
+   |     ^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:17:5
+   |
+LL |     x > NAN_F32;
+   |     ^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:18:5
+   |
+LL |     x <= NAN_F32;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:19:5
+   |
+LL |     x >= NAN_F32;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:22:5
+   |
+LL |     y == f64::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:23:5
+   |
+LL |     y != f64::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:24:5
+   |
+LL |     y < f64::NAN;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:25:5
+   |
+LL |     y > f64::NAN;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:26:5
+   |
+LL |     y <= f64::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:27:5
+   |
+LL |     y >= f64::NAN;
+   |     ^^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:28:5
+   |
+LL |     y == NAN_F64;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:29:5
+   |
+LL |     y != NAN_F64;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:30:5
+   |
+LL |     y < NAN_F64;
+   |     ^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:31:5
+   |
+LL |     y > NAN_F64;
+   |     ^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:32:5
+   |
+LL |     y <= NAN_F64;
+   |     ^^^^^^^^^^^^
+
+error: doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead
+  --> $DIR/cmp_nan.rs:33:5
+   |
+LL |     y >= NAN_F64;
+   |     ^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs
new file mode 100644
index 00000000000..2d2d04178c3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_null.rs
@@ -0,0 +1,17 @@
+#![warn(clippy::cmp_null)]
+#![allow(unused_mut)]
+
+use std::ptr;
+
+fn main() {
+    let x = 0;
+    let p: *const usize = &x;
+    if p == ptr::null() {
+        println!("This is surprising!");
+    }
+    let mut y = 0;
+    let mut m: *mut usize = &mut y;
+    if m == ptr::null_mut() {
+        println!("This is surprising, too!");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr
new file mode 100644
index 00000000000..b563a2ebec2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_null.stderr
@@ -0,0 +1,16 @@
+error: Comparing with null is better expressed by the `.is_null()` method
+  --> $DIR/cmp_null.rs:9:8
+   |
+LL |     if p == ptr::null() {
+   |        ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cmp-null` implied by `-D warnings`
+
+error: Comparing with null is better expressed by the `.is_null()` method
+  --> $DIR/cmp_null.rs:14:8
+   |
+LL |     if m == ptr::null_mut() {
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
new file mode 100644
index 00000000000..05fb96339e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
@@ -0,0 +1,72 @@
+// run-rustfix
+
+#[warn(clippy::cmp_owned)]
+#[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)]
+fn main() {
+    fn with_to_string(x: &str) {
+        x != "foo";
+
+        "foo" != x;
+    }
+
+    let x = "oh";
+
+    with_to_string(x);
+
+    x != "foo";
+
+    x != "foo";
+
+    42.to_string() == "42";
+
+    Foo == Foo;
+
+    "abc".chars().filter(|c| *c != 'X');
+
+    "abc".chars().filter(|c| *c != 'X');
+}
+
+struct Foo;
+
+impl PartialEq for Foo {
+    // Allow this here, because it emits the lint
+    // without a suggestion. This is tested in
+    // `tests/ui/cmp_owned/without_suggestion.rs`
+    #[allow(clippy::cmp_owned)]
+    fn eq(&self, other: &Self) -> bool {
+        self.to_owned() == *other
+    }
+}
+
+impl ToOwned for Foo {
+    type Owned = Bar;
+    fn to_owned(&self) -> Bar {
+        Bar
+    }
+}
+
+#[derive(PartialEq)]
+struct Bar;
+
+impl PartialEq<Foo> for Bar {
+    fn eq(&self, _: &Foo) -> bool {
+        true
+    }
+}
+
+impl std::borrow::Borrow<Foo> for Bar {
+    fn borrow(&self) -> &Foo {
+        static FOO: Foo = Foo;
+        &FOO
+    }
+}
+
+#[derive(PartialEq)]
+struct Baz;
+
+impl ToOwned for Baz {
+    type Owned = Baz;
+    fn to_owned(&self) -> Baz {
+        Baz
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
new file mode 100644
index 00000000000..0a02825ed82
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
@@ -0,0 +1,72 @@
+// run-rustfix
+
+#[warn(clippy::cmp_owned)]
+#[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)]
+fn main() {
+    fn with_to_string(x: &str) {
+        x != "foo".to_string();
+
+        "foo".to_string() != x;
+    }
+
+    let x = "oh";
+
+    with_to_string(x);
+
+    x != "foo".to_owned();
+
+    x != String::from("foo");
+
+    42.to_string() == "42";
+
+    Foo.to_owned() == Foo;
+
+    "abc".chars().filter(|c| c.to_owned() != 'X');
+
+    "abc".chars().filter(|c| *c != 'X');
+}
+
+struct Foo;
+
+impl PartialEq for Foo {
+    // Allow this here, because it emits the lint
+    // without a suggestion. This is tested in
+    // `tests/ui/cmp_owned/without_suggestion.rs`
+    #[allow(clippy::cmp_owned)]
+    fn eq(&self, other: &Self) -> bool {
+        self.to_owned() == *other
+    }
+}
+
+impl ToOwned for Foo {
+    type Owned = Bar;
+    fn to_owned(&self) -> Bar {
+        Bar
+    }
+}
+
+#[derive(PartialEq)]
+struct Bar;
+
+impl PartialEq<Foo> for Bar {
+    fn eq(&self, _: &Foo) -> bool {
+        true
+    }
+}
+
+impl std::borrow::Borrow<Foo> for Bar {
+    fn borrow(&self) -> &Foo {
+        static FOO: Foo = Foo;
+        &FOO
+    }
+}
+
+#[derive(PartialEq)]
+struct Baz;
+
+impl ToOwned for Baz {
+    type Owned = Baz;
+    fn to_owned(&self) -> Baz {
+        Baz
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr
new file mode 100644
index 00000000000..2f333e6ea8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr
@@ -0,0 +1,40 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:7:14
+   |
+LL |         x != "foo".to_string();
+   |              ^^^^^^^^^^^^^^^^^ help: try: `"foo"`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:9:9
+   |
+LL |         "foo".to_string() != x;
+   |         ^^^^^^^^^^^^^^^^^ help: try: `"foo"`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:16:10
+   |
+LL |     x != "foo".to_owned();
+   |          ^^^^^^^^^^^^^^^^ help: try: `"foo"`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:18:10
+   |
+LL |     x != String::from("foo");
+   |          ^^^^^^^^^^^^^^^^^^^ help: try: `"foo"`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:22:5
+   |
+LL |     Foo.to_owned() == Foo;
+   |     ^^^^^^^^^^^^^^ help: try: `Foo`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/with_suggestion.rs:24:30
+   |
+LL |     "abc".chars().filter(|c| c.to_owned() != 'X');
+   |                              ^^^^^^^^^^^^ help: try: `*c`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs
new file mode 100644
index 00000000000..9ab8795474c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs
@@ -0,0 +1,52 @@
+#[allow(clippy::unnecessary_operation)]
+
+fn main() {
+    let x = &Baz;
+    let y = &Baz;
+    y.to_owned() == *x;
+
+    let x = &&Baz;
+    let y = &Baz;
+    y.to_owned() == **x;
+}
+
+struct Foo;
+
+impl PartialEq for Foo {
+    fn eq(&self, other: &Self) -> bool {
+        self.to_owned() == *other
+    }
+}
+
+impl ToOwned for Foo {
+    type Owned = Bar;
+    fn to_owned(&self) -> Bar {
+        Bar
+    }
+}
+
+#[derive(PartialEq)]
+struct Baz;
+
+impl ToOwned for Baz {
+    type Owned = Baz;
+    fn to_owned(&self) -> Baz {
+        Baz
+    }
+}
+
+#[derive(PartialEq)]
+struct Bar;
+
+impl PartialEq<Foo> for Bar {
+    fn eq(&self, _: &Foo) -> bool {
+        true
+    }
+}
+
+impl std::borrow::Borrow<Foo> for Bar {
+    fn borrow(&self) -> &Foo {
+        static FOO: Foo = Foo;
+        &FOO
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr
new file mode 100644
index 00000000000..6e8a5ad2a17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr
@@ -0,0 +1,22 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/without_suggestion.rs:6:5
+   |
+LL |     y.to_owned() == *x;
+   |     ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/without_suggestion.rs:10:5
+   |
+LL |     y.to_owned() == **x;
+   |     ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
+
+error: this creates an owned instance just for comparison
+  --> $DIR/without_suggestion.rs:17:9
+   |
+LL |         self.to_owned() == *other
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.rs b/src/tools/clippy/tests/ui/cognitive_complexity.rs
new file mode 100644
index 00000000000..1d3fe405521
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cognitive_complexity.rs
@@ -0,0 +1,395 @@
+#![allow(clippy::all)]
+#![warn(clippy::cognitive_complexity)]
+#![allow(unused)]
+
+#[rustfmt::skip]
+fn main() {
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn kaboom() {
+    let n = 0;
+    'a: for i in 0..20 {
+        'b: for j in i..20 {
+            for k in j..20 {
+                if k == 5 {
+                    break 'b;
+                }
+                if j == 3 && k == 6 {
+                    continue 'a;
+                }
+                if k == j {
+                    continue;
+                }
+                println!("bake");
+            }
+        }
+        println!("cake");
+    }
+}
+
+fn bloo() {
+    match 42 {
+        0 => println!("hi"),
+        1 => println!("hai"),
+        2 => println!("hey"),
+        3 => println!("hallo"),
+        4 => println!("hello"),
+        5 => println!("salut"),
+        6 => println!("good morning"),
+        7 => println!("good evening"),
+        8 => println!("good afternoon"),
+        9 => println!("good night"),
+        10 => println!("bonjour"),
+        11 => println!("hej"),
+        12 => println!("hej hej"),
+        13 => println!("greetings earthling"),
+        14 => println!("take us to you leader"),
+        15 | 17 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 => println!("take us to you leader"),
+        35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 => println!("there is no undefined behavior"),
+        55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 73 => println!("I know borrow-fu"),
+        _ => println!("bye"),
+    }
+}
+
+// Short circuiting operations don't increase the complexity of a function.
+// Note that the minimum complexity of a function is 1.
+#[clippy::cognitive_complexity = "1"]
+fn lots_of_short_circuits() -> bool {
+    true && false && true && false && true && false && true
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn lots_of_short_circuits2() -> bool {
+    true || false || true || false || true || false || true
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn baa() {
+    let x = || match 99 {
+        0 => 0,
+        1 => 1,
+        2 => 2,
+        4 => 4,
+        6 => 6,
+        9 => 9,
+        _ => 42,
+    };
+    if x() == 42 {
+        println!("x");
+    } else {
+        println!("not x");
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn bar() {
+    match 99 {
+        0 => println!("hi"),
+        _ => println!("bye"),
+    }
+}
+
+#[test]
+#[clippy::cognitive_complexity = "1"]
+/// Tests are usually complex but simple at the same time. `clippy::cognitive_complexity` used to
+/// give lots of false-positives in tests.
+fn dont_warn_on_tests() {
+    match 99 {
+        0 => println!("hi"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barrr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barrr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barrrr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn barrrr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn cake() {
+    if 4 == 5 {
+        println!("yea");
+    } else {
+        panic!("meh");
+    }
+    println!("whee");
+}
+
+#[clippy::cognitive_complexity = "1"]
+pub fn read_file(input_path: &str) -> String {
+    use std::fs::File;
+    use std::io::{Read, Write};
+    use std::path::Path;
+    let mut file = match File::open(&Path::new(input_path)) {
+        Ok(f) => f,
+        Err(err) => {
+            panic!("Can't open {}: {}", input_path, err);
+        },
+    };
+
+    let mut bytes = Vec::new();
+
+    match file.read_to_end(&mut bytes) {
+        Ok(..) => {},
+        Err(_) => {
+            panic!("Can't read {}", input_path);
+        },
+    };
+
+    match String::from_utf8(bytes) {
+        Ok(contents) => contents,
+        Err(_) => {
+            panic!("{} is not UTF-8 encoded", input_path);
+        },
+    }
+}
+
+enum Void {}
+
+#[clippy::cognitive_complexity = "1"]
+fn void(void: Void) {
+    if true {
+        match void {}
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn mcarton_sees_all() {
+    panic!("meh");
+    panic!("möh");
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn try_() -> Result<i32, &'static str> {
+    match 5 {
+        5 => Ok(5),
+        _ => return Err("bla"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn try_again() -> Result<i32, &'static str> {
+    let _ = Ok(42)?;
+    let _ = Ok(43)?;
+    let _ = Ok(44)?;
+    let _ = Ok(45)?;
+    let _ = Ok(46)?;
+    let _ = Ok(47)?;
+    let _ = Ok(48)?;
+    let _ = Ok(49)?;
+    match 5 {
+        5 => Ok(5),
+        _ => return Err("bla"),
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn early() -> Result<i32, &'static str> {
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+}
+
+#[rustfmt::skip]
+#[clippy::cognitive_complexity = "1"]
+fn early_ret() -> i32 {
+    let a = if true { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    match 5 {
+        5 => 5,
+        _ => return 6,
+    }
+}
+
+#[clippy::cognitive_complexity = "1"]
+fn closures() {
+    let x = |a: i32, b: i32| -> i32 {
+        if true {
+            println!("moo");
+        }
+
+        a + b
+    };
+}
+
+struct Moo;
+
+#[clippy::cognitive_complexity = "1"]
+impl Moo {
+    fn moo(&self) {
+        if true {
+            println!("moo");
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.stderr b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
new file mode 100644
index 00000000000..a0ddc673abc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
@@ -0,0 +1,139 @@
+error: the function has a cognitive complexity of (28/25)
+  --> $DIR/cognitive_complexity.rs:6:4
+   |
+LL | fn main() {
+   |    ^^^^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (7/1)
+  --> $DIR/cognitive_complexity.rs:91:4
+   |
+LL | fn kaboom() {
+   |    ^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:149:4
+   |
+LL | fn baa() {
+   |    ^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:150:13
+   |
+LL |     let x = || match 99 {
+   |             ^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:167:4
+   |
+LL | fn bar() {
+   |    ^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:186:4
+   |
+LL | fn barr() {
+   |    ^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (3/1)
+  --> $DIR/cognitive_complexity.rs:196:4
+   |
+LL | fn barr2() {
+   |    ^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:212:4
+   |
+LL | fn barrr() {
+   |    ^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (3/1)
+  --> $DIR/cognitive_complexity.rs:222:4
+   |
+LL | fn barrr2() {
+   |    ^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:238:4
+   |
+LL | fn barrrr() {
+   |    ^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (3/1)
+  --> $DIR/cognitive_complexity.rs:248:4
+   |
+LL | fn barrrr2() {
+   |    ^^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:264:4
+   |
+LL | fn cake() {
+   |    ^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (4/1)
+  --> $DIR/cognitive_complexity.rs:274:8
+   |
+LL | pub fn read_file(input_path: &str) -> String {
+   |        ^^^^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:305:4
+   |
+LL | fn void(void: Void) {
+   |    ^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (8/1)
+  --> $DIR/cognitive_complexity.rs:356:4
+   |
+LL | fn early_ret() -> i32 {
+   |    ^^^^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:377:13
+   |
+LL |     let x = |a: i32, b: i32| -> i32 {
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+  --> $DIR/cognitive_complexity.rs:390:8
+   |
+LL |     fn moo(&self) {
+   |        ^^^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs
new file mode 100644
index 00000000000..403eff566ed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs
@@ -0,0 +1,15 @@
+#![warn(clippy::cognitive_complexity)]
+#![warn(unused)]
+
+fn main() {
+    kaboom();
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn kaboom() {
+    if 42 == 43 {
+        panic!();
+    } else if "cake" == "lie" {
+        println!("what?");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr
new file mode 100644
index 00000000000..f5ff53dda60
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr
@@ -0,0 +1,11 @@
+error: the function has a cognitive complexity of (3/0)
+  --> $DIR/cognitive_complexity_attr_used.rs:9:4
+   |
+LL | fn kaboom() {
+   |    ^^^^^^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
new file mode 100644
index 00000000000..ce2a1c28c8a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed
@@ -0,0 +1,66 @@
+// run-rustfix
+#![allow(clippy::assertions_on_constants)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let x = "hello";
+    let y = "world";
+    // Collapse `else { if .. }` to `else if ..`
+    if x == "hello" {
+        print!("Hello ");
+    } else if y == "world" {
+        println!("world!")
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+        println!("world!")
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if y == "world" {
+        println!("world")
+    }
+    else {
+        println!("!")
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+        println!("world")
+    }
+    else {
+        println!("!")
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+        println!("world")
+    }
+    else {
+        println!("!")
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if x == "hello" {
+        println!("world")
+    }
+    else {
+        println!("!")
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+        println!("world")
+    }
+    else {
+        println!("!")
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs
new file mode 100644
index 00000000000..99c40b8d38e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs
@@ -0,0 +1,80 @@
+// run-rustfix
+#![allow(clippy::assertions_on_constants)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let x = "hello";
+    let y = "world";
+    // Collapse `else { if .. }` to `else if ..`
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        if let Some(42) = Some(42) {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        if y == "world" {
+            println!("world")
+        }
+        else {
+            println!("!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        if let Some(42) = Some(42) {
+            println!("world")
+        }
+        else {
+            println!("!")
+        }
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else {
+        if let Some(42) = Some(42) {
+            println!("world")
+        }
+        else {
+            println!("!")
+        }
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else {
+        if x == "hello" {
+            println!("world")
+        }
+        else {
+            println!("!")
+        }
+    }
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else {
+        if let Some(42) = Some(42) {
+            println!("world")
+        }
+        else {
+            println!("!")
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr
new file mode 100644
index 00000000000..28048999e8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr
@@ -0,0 +1,154 @@
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:12:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if y == "world" {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::collapsible-if` implied by `-D warnings`
+help: try
+   |
+LL |     } else if y == "world" {
+LL |         println!("world!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:20:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if let Some(42) = Some(42) {
+LL |         println!("world!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:28:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if y == "world" {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if y == "world" {
+LL |         println!("world")
+LL |     }
+LL |     else {
+LL |         println!("!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:39:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if let Some(42) = Some(42) {
+LL |         println!("world")
+LL |     }
+LL |     else {
+LL |         println!("!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:50:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if let Some(42) = Some(42) {
+LL |         println!("world")
+LL |     }
+LL |     else {
+LL |         println!("!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:61:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if x == "hello" {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if x == "hello" {
+LL |         println!("world")
+LL |     }
+LL |     else {
+LL |         println!("!")
+LL |     }
+   |
+
+error: this `else { if .. }` block can be collapsed
+  --> $DIR/collapsible_else_if.rs:72:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     } else if let Some(42) = Some(42) {
+LL |         println!("world")
+LL |     }
+LL |     else {
+LL |         println!("!")
+LL |     }
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
new file mode 100644
index 00000000000..561283fc8e7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -0,0 +1,138 @@
+// run-rustfix
+#![allow(clippy::assertions_on_constants)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let x = "hello";
+    let y = "world";
+    if x == "hello" && y == "world" {
+        println!("Hello world!");
+    }
+
+    if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
+        println!("Hello world!");
+    }
+
+    if x == "hello" && x == "world" && (y == "world" || y == "hello") {
+        println!("Hello world!");
+    }
+
+    if (x == "hello" || x == "world") && y == "world" && y == "hello" {
+        println!("Hello world!");
+    }
+
+    if x == "hello" && x == "world" && y == "world" && y == "hello" {
+        println!("Hello world!");
+    }
+
+    if 42 == 1337 && 'a' != 'A' {
+        println!("world!")
+    }
+
+    // Works because any if with an else statement cannot be collapsed.
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        }
+    } else {
+        println!("Not Hello world");
+    }
+
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        } else {
+            println!("Hello something else");
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if true {
+    } else {
+        assert!(true); // assert! is just an `if`
+    }
+
+
+    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+    if x == "hello" {// Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" && y == "world" { // Collapsible
+        println!("Hello world!");
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if let Some(42) = Some(42) {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    // Test behavior wrt. `let_chains`.
+    // None of the cases below should be collapsed.
+    fn truth() -> bool { true }
+
+    // Prefix:
+    if let 0 = 1 {
+        if truth() {}
+    }
+
+    // Suffix:
+    if truth() {
+        if let 0 = 1 {}
+    }
+
+    // Midfix:
+    if truth() {
+        if let 0 = 1 {
+            if truth() {}
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
new file mode 100644
index 00000000000..dc9d9b451c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -0,0 +1,152 @@
+// run-rustfix
+#![allow(clippy::assertions_on_constants)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let x = "hello";
+    let y = "world";
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" || x == "world" {
+        if y == "world" || y == "hello" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" && x == "world" {
+        if y == "world" || y == "hello" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" || x == "world" {
+        if y == "world" && y == "hello" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" && x == "world" {
+        if y == "world" && y == "hello" {
+            println!("Hello world!");
+        }
+    }
+
+    if 42 == 1337 {
+        if 'a' != 'A' {
+            println!("world!")
+        }
+    }
+
+    // Works because any if with an else statement cannot be collapsed.
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        }
+    } else {
+        println!("Not Hello world");
+    }
+
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        } else {
+            println!("Hello something else");
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if true {
+    } else {
+        assert!(true); // assert! is just an `if`
+    }
+
+
+    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+    if x == "hello" {// Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        if y == "world" { // Collapsible
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if let Some(42) = Some(42) {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    // Test behavior wrt. `let_chains`.
+    // None of the cases below should be collapsed.
+    fn truth() -> bool { true }
+
+    // Prefix:
+    if let 0 = 1 {
+        if truth() {}
+    }
+
+    // Suffix:
+    if truth() {
+        if let 0 = 1 {}
+    }
+
+    // Midfix:
+    if truth() {
+        if let 0 = 1 {
+            if truth() {}
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr
new file mode 100644
index 00000000000..6440ff41be8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if.stderr
@@ -0,0 +1,122 @@
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:9:5
+   |
+LL | /     if x == "hello" {
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::collapsible-if` implied by `-D warnings`
+help: try
+   |
+LL |     if x == "hello" && y == "world" {
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:15:5
+   |
+LL | /     if x == "hello" || x == "world" {
+LL | |         if y == "world" || y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:21:5
+   |
+LL | /     if x == "hello" && x == "world" {
+LL | |         if y == "world" || y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if x == "hello" && x == "world" && (y == "world" || y == "hello") {
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:27:5
+   |
+LL | /     if x == "hello" || x == "world" {
+LL | |         if y == "world" && y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if (x == "hello" || x == "world") && y == "world" && y == "hello" {
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:33:5
+   |
+LL | /     if x == "hello" && x == "world" {
+LL | |         if y == "world" && y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if x == "hello" && x == "world" && y == "world" && y == "hello" {
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:39:5
+   |
+LL | /     if 42 == 1337 {
+LL | |         if 'a' != 'A' {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if 42 == 1337 && 'a' != 'A' {
+LL |         println!("world!")
+LL |     }
+   |
+
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:95:5
+   |
+LL | /     if x == "hello" {
+LL | |         if y == "world" { // Collapsible
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if x == "hello" && y == "world" { // Collapsible
+LL |         println!("Hello world!");
+LL |     }
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_span_lint_calls.fixed b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.fixed
new file mode 100644
index 00000000000..e588c23345e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.fixed
@@ -0,0 +1,91 @@
+// run-rustfix
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_ast;
+extern crate rustc_errors;
+extern crate rustc_lint;
+extern crate rustc_session;
+extern crate rustc_span;
+
+use rustc_ast::ast::Expr;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
+
+#[allow(unused_variables)]
+pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
+where
+    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
+{
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_help<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    option_span: Option<Span>,
+    help: &str,
+) {
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_note<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    note_span: Option<Span>,
+    note: &str,
+) {
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_sugg<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    sp: Span,
+    msg: &str,
+    help: &str,
+    sugg: String,
+    applicability: Applicability,
+) {
+}
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+impl EarlyLintPass for Pass {
+    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
+        let lint_msg = "lint message";
+        let help_msg = "help message";
+        let note_msg = "note message";
+        let sugg = "new_call()";
+        let predicate = true;
+
+        span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable);
+        span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
+        span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
+        span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
+        span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
+
+        // This expr shouldn't trigger this lint.
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.note(note_msg);
+            if predicate {
+                db.note(note_msg);
+            }
+        })
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/collapsible_span_lint_calls.rs b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.rs
new file mode 100644
index 00000000000..d5dd3bb562b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.rs
@@ -0,0 +1,101 @@
+// run-rustfix
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_ast;
+extern crate rustc_errors;
+extern crate rustc_lint;
+extern crate rustc_session;
+extern crate rustc_span;
+
+use rustc_ast::ast::Expr;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
+
+#[allow(unused_variables)]
+pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
+where
+    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
+{
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_help<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    option_span: Option<Span>,
+    help: &str,
+) {
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_note<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    note_span: Option<Span>,
+    note: &str,
+) {
+}
+
+#[allow(unused_variables)]
+fn span_lint_and_sugg<'a, T: LintContext>(
+    cx: &'a T,
+    lint: &'static Lint,
+    sp: Span,
+    msg: &str,
+    help: &str,
+    sugg: String,
+    applicability: Applicability,
+) {
+}
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+impl EarlyLintPass for Pass {
+    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
+        let lint_msg = "lint message";
+        let help_msg = "help message";
+        let note_msg = "note message";
+        let sugg = "new_call()";
+        let predicate = true;
+
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
+        });
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.span_help(expr.span, help_msg);
+        });
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.help(help_msg);
+        });
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.span_note(expr.span, note_msg);
+        });
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.note(note_msg);
+        });
+
+        // This expr shouldn't trigger this lint.
+        span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+            db.note(note_msg);
+            if predicate {
+                db.note(note_msg);
+            }
+        })
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/collapsible_span_lint_calls.stderr b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.stderr
new file mode 100644
index 00000000000..874d4a9f255
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_span_lint_calls.stderr
@@ -0,0 +1,49 @@
+error: this call is collapsible
+  --> $DIR/collapsible_span_lint_calls.rs:75:9
+   |
+LL | /         span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+LL | |             db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
+LL | |         });
+   | |__________^ help: collapse into: `span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable)`
+   |
+note: the lint level is defined here
+  --> $DIR/collapsible_span_lint_calls.rs:2:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
+
+error: this call is collapsible
+  --> $DIR/collapsible_span_lint_calls.rs:78:9
+   |
+LL | /         span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+LL | |             db.span_help(expr.span, help_msg);
+LL | |         });
+   | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)`
+
+error: this call is collapsible
+  --> $DIR/collapsible_span_lint_calls.rs:81:9
+   |
+LL | /         span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+LL | |             db.help(help_msg);
+LL | |         });
+   | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)`
+
+error: this call is collspible
+  --> $DIR/collapsible_span_lint_calls.rs:84:9
+   |
+LL | /         span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+LL | |             db.span_note(expr.span, note_msg);
+LL | |         });
+   | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)`
+
+error: this call is collspible
+  --> $DIR/collapsible_span_lint_calls.rs:87:9
+   |
+LL | /         span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
+LL | |             db.note(note_msg);
+LL | |         });
+   | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg)`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/comparison_chain.rs b/src/tools/clippy/tests/ui/comparison_chain.rs
new file mode 100644
index 00000000000..9c2128469de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/comparison_chain.rs
@@ -0,0 +1,140 @@
+#![allow(dead_code)]
+#![warn(clippy::comparison_chain)]
+
+fn a() {}
+fn b() {}
+fn c() {}
+
+fn f(x: u8, y: u8, z: u8) {
+    // Ignored: Only one branch
+    if x > y {
+        a()
+    }
+
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    }
+
+    // Ignored: Only one explicit conditional
+    if x > y {
+        a()
+    } else {
+        b()
+    }
+
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    } else {
+        c()
+    }
+
+    if x > y {
+        a()
+    } else if y > x {
+        b()
+    } else {
+        c()
+    }
+
+    if x > 1 {
+        a()
+    } else if x < 1 {
+        b()
+    } else if x == 1 {
+        c()
+    }
+
+    // Ignored: Binop args are not equivalent
+    if x > 1 {
+        a()
+    } else if y > 1 {
+        b()
+    } else {
+        c()
+    }
+
+    // Ignored: Binop args are not equivalent
+    if x > y {
+        a()
+    } else if x > z {
+        b()
+    } else if y > z {
+        c()
+    }
+
+    // Ignored: Not binary comparisons
+    if true {
+        a()
+    } else if false {
+        b()
+    } else {
+        c()
+    }
+}
+
+#[allow(clippy::float_cmp)]
+fn g(x: f64, y: f64, z: f64) {
+    // Ignored: f64 doesn't implement Ord
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    }
+
+    // Ignored: f64 doesn't implement Ord
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    } else {
+        c()
+    }
+
+    // Ignored: f64 doesn't implement Ord
+    if x > y {
+        a()
+    } else if y > x {
+        b()
+    } else {
+        c()
+    }
+
+    // Ignored: f64 doesn't implement Ord
+    if x > 1.0 {
+        a()
+    } else if x < 1.0 {
+        b()
+    } else if x == 1.0 {
+        c()
+    }
+}
+
+fn h<T: Ord>(x: T, y: T, z: T) {
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    }
+
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    } else {
+        c()
+    }
+
+    if x > y {
+        a()
+    } else if y > x {
+        b()
+    } else {
+        c()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr
new file mode 100644
index 00000000000..69db88b03b5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/comparison_chain.stderr
@@ -0,0 +1,97 @@
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:14:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if x < y {
+LL | |         b()
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::comparison-chain` implied by `-D warnings`
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:27:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if x < y {
+LL | |         b()
+LL | |     } else {
+LL | |         c()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:35:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if y > x {
+LL | |         b()
+LL | |     } else {
+LL | |         c()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:43:5
+   |
+LL | /     if x > 1 {
+LL | |         a()
+LL | |     } else if x < 1 {
+LL | |         b()
+LL | |     } else if x == 1 {
+LL | |         c()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:117:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if x < y {
+LL | |         b()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:123:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if x < y {
+LL | |         b()
+LL | |     } else {
+LL | |         c()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: `if` chain can be rewritten with `match`
+  --> $DIR/comparison_chain.rs:131:5
+   |
+LL | /     if x > y {
+LL | |         a()
+LL | |     } else if y > x {
+LL | |         b()
+LL | |     } else {
+LL | |         c()
+LL | |     }
+   | |_____^
+   |
+   = help: Consider rewriting the `if` chain to use `cmp` and `match`.
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/complex_types.rs b/src/tools/clippy/tests/ui/complex_types.rs
new file mode 100644
index 00000000000..be61fb6b9be
--- /dev/null
+++ b/src/tools/clippy/tests/ui/complex_types.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::all)]
+#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)]
+#![feature(associated_type_defaults)]
+
+type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here
+
+const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+
+struct S {
+    f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
+}
+
+struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+
+enum E {
+    Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
+    Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
+}
+
+impl S {
+    const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+    fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+}
+
+trait T {
+    const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+    type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+    fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+    fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+}
+
+fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
+    vec![]
+}
+
+fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+
+fn test3() {
+    let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
+}
+
+#[repr(C)]
+struct D {
+    // should not warn, since we don't have control over the signature (#3222)
+    test4: extern "C" fn(
+        itself: &D,
+        a: usize,
+        b: usize,
+        c: usize,
+        d: usize,
+        e: usize,
+        f: usize,
+        g: usize,
+        h: usize,
+        i: usize,
+    ),
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/complex_types.stderr b/src/tools/clippy/tests/ui/complex_types.stderr
new file mode 100644
index 00000000000..8f5dbd27956
--- /dev/null
+++ b/src/tools/clippy/tests/ui/complex_types.stderr
@@ -0,0 +1,94 @@
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:7:12
+   |
+LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::type-complexity` implied by `-D warnings`
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:8:12
+   |
+LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:11:8
+   |
+LL |     f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:14:11
+   |
+LL | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:17:11
+   |
+LL |     Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:18:17
+   |
+LL |     Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:22:14
+   |
+LL |     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:23:30
+   |
+LL |     fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:27:14
+   |
+LL |     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:28:14
+   |
+LL |     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:29:25
+   |
+LL |     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:30:29
+   |
+LL |     fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:33:15
+   |
+LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:37:14
+   |
+LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: very complex type used. Consider factoring parts into `type` definitions
+  --> $DIR/complex_types.rs:40:13
+   |
+LL |     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/copy_iterator.rs b/src/tools/clippy/tests/ui/copy_iterator.rs
new file mode 100644
index 00000000000..e3d5928be23
--- /dev/null
+++ b/src/tools/clippy/tests/ui/copy_iterator.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::copy_iterator)]
+
+#[derive(Copy, Clone)]
+struct Countdown(u8);
+
+impl Iterator for Countdown {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<u8> {
+        self.0.checked_sub(1).map(|c| {
+            self.0 = c;
+            c
+        })
+    }
+}
+
+fn main() {
+    let my_iterator = Countdown(5);
+    let a: Vec<_> = my_iterator.take(1).collect();
+    assert_eq!(a.len(), 1);
+    let b: Vec<_> = my_iterator.collect();
+    assert_eq!(b.len(), 5);
+}
diff --git a/src/tools/clippy/tests/ui/copy_iterator.stderr b/src/tools/clippy/tests/ui/copy_iterator.stderr
new file mode 100644
index 00000000000..f8ce6af7961
--- /dev/null
+++ b/src/tools/clippy/tests/ui/copy_iterator.stderr
@@ -0,0 +1,17 @@
+error: you are implementing `Iterator` on a `Copy` type
+  --> $DIR/copy_iterator.rs:6:1
+   |
+LL | / impl Iterator for Countdown {
+LL | |     type Item = u8;
+LL | |
+LL | |     fn next(&mut self) -> Option<u8> {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::copy-iterator` implied by `-D warnings`
+   = note: consider implementing `IntoIterator` instead
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
new file mode 100644
index 00000000000..4bb833795bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1698
+
+pub trait Trait {
+    const CONSTANT: u8;
+}
+
+impl Trait for u8 {
+    const CONSTANT: u8 = 2;
+}
+
+fn main() {
+    println!("{}", u8::CONSTANT * 10);
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-4727-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-4727-aux.rs
new file mode 100644
index 00000000000..58a20caf6c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-4727-aux.rs
@@ -0,0 +1,9 @@
+pub trait Trait {
+    fn fun(par: &str) -> &str;
+}
+
+impl Trait for str {
+    fn fun(par: &str) -> &str {
+        &par[0..1]
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
new file mode 100644
index 00000000000..086548e58ed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -0,0 +1,37 @@
+// no-prefer-dynamic
+// ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
+// crates. If we don't set this, compiletest will override the `crate_type` attribute below and
+// compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't
+// contain a proc-macro.
+
+#![feature(repr128)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
+
+#[proc_macro]
+pub fn macro_test(input_stream: TokenStream) -> TokenStream {
+    let first_token = input_stream.into_iter().next().unwrap();
+    let span = first_token.span();
+
+    TokenStream::from_iter(vec![
+        TokenTree::Ident(Ident::new("fn", Span::call_site())),
+        TokenTree::Ident(Ident::new("code", Span::call_site())),
+        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
+        TokenTree::Group(Group::new(Delimiter::Brace, {
+            let mut clause = Group::new(Delimiter::Brace, TokenStream::new());
+            clause.set_span(span);
+
+            TokenStream::from_iter(vec![
+                TokenTree::Ident(Ident::new("if", Span::call_site())),
+                TokenTree::Ident(Ident::new("true", Span::call_site())),
+                TokenTree::Group(clause.clone()),
+                TokenTree::Ident(Ident::new("else", Span::call_site())),
+                TokenTree::Group(clause),
+            ])
+        })),
+    ])
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/use_self_macro.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/use_self_macro.rs
new file mode 100644
index 00000000000..a8a85b4baef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/use_self_macro.rs
@@ -0,0 +1,15 @@
+macro_rules! use_self {
+    (
+        impl $ty:ident {
+            fn func(&$this:ident) {
+                [fields($($field:ident)*)]
+            }
+        }
+    ) => (
+        impl  $ty {
+            fn func(&$this) {
+                let $ty { $($field),* } = $this;
+            }
+        }
+    )
+}
diff --git a/src/tools/clippy/tests/ui/crashes/cc_seme.rs b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
new file mode 100644
index 00000000000..c48c7e9e6c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
@@ -0,0 +1,29 @@
+// run-pass
+
+#[allow(dead_code)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/478
+
+enum Baz {
+    One,
+    Two,
+}
+
+struct Test {
+    t: Option<usize>,
+    b: Baz,
+}
+
+fn main() {}
+
+pub fn foo() {
+    use Baz::*;
+    let x = Test { t: Some(0), b: One };
+
+    match x {
+        Test { t: Some(_), b: One } => unreachable!(),
+        Test { t: Some(42), b: Two } => unreachable!(),
+        Test { t: None, .. } => unreachable!(),
+        Test { .. } => unreachable!(),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
new file mode 100644
index 00000000000..db1fa871afe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+#![deny(clippy::all)]
+#![allow(unused_imports)]
+
+use std::*;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
new file mode 100644
index 00000000000..15d0f705b36
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1588
+
+fn main() {
+    match 1 {
+        1 => {},
+        2 => {
+            [0; 1];
+        },
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
new file mode 100644
index 00000000000..1ca6b6976b3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![allow(dead_code, unused_variables)]
+
+/// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/1782
+use std::{mem, ptr};
+
+fn spanless_eq_ice() {
+    let txt = "something";
+    match txt {
+        "something" => unsafe {
+            ptr::write(
+                ptr::null_mut() as *mut u32,
+                mem::transmute::<[u8; 4], _>([0, 0, 0, 255]),
+            )
+        },
+        _ => unsafe {
+            ptr::write(
+                ptr::null_mut() as *mut u32,
+                mem::transmute::<[u8; 4], _>([13, 246, 24, 255]),
+            )
+        },
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
new file mode 100644
index 00000000000..837ec9df31a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1969
+
+fn main() {}
+
+pub trait Convert {
+    type Action: From<*const f64>;
+
+    fn convert(val: *const f64) -> Self::Action {
+        val.into()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2499.rs b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
new file mode 100644
index 00000000000..ffef1631775
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
+
+/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499
+
+fn f(s: &[u8]) -> bool {
+    let t = s[0] as char;
+
+    match t {
+        'E' | 'W' => {},
+        'T' => {
+            if s[0..4] != ['0' as u8; 4] {
+                return false;
+            } else {
+                return true;
+            }
+        },
+        _ => {
+            return false;
+        },
+    }
+    true
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2594.rs b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
new file mode 100644
index 00000000000..ac19f1976e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+#![allow(dead_code, unused_variables)]
+
+/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2594
+
+fn spanless_hash_ice() {
+    let txt = "something";
+    let empty_header: [u8; 1] = [1; 1];
+
+    match txt {
+        "something" => {
+            let mut headers = [empty_header; 1];
+        },
+        "" => (),
+        _ => (),
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2636.rs b/src/tools/clippy/tests/ui/crashes/ice-2636.rs
new file mode 100644
index 00000000000..e0b58157590
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2636.rs
@@ -0,0 +1,22 @@
+#![allow(dead_code)]
+
+enum Foo {
+    A,
+    B,
+    C,
+}
+
+macro_rules! test_hash {
+    ($foo:expr, $($t:ident => $ord:expr),+ ) => {
+        use self::Foo::*;
+        match $foo {
+            $ ( & $t => $ord,
+            )*
+        };
+    };
+}
+
+fn main() {
+    let a = Foo::A;
+    test_hash!(&a, A => 0, B => 1, C => 2);
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2636.stderr b/src/tools/clippy/tests/ui/crashes/ice-2636.stderr
new file mode 100644
index 00000000000..53799b4fbf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2636.stderr
@@ -0,0 +1,17 @@
+error: you don't need to add `&` to both the expression and the patterns
+  --> $DIR/ice-2636.rs:12:9
+   |
+LL | /         match $foo {
+LL | |             $ ( & $t => $ord,
+LL | |             )*
+LL | |         };
+   | |_________^
+...
+LL |       test_hash!(&a, A => 0, B => 1, C => 2);
+   |       --------------------------------------- in this macro invocation
+   |
+   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2727.rs b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
new file mode 100644
index 00000000000..d832c286033
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2727
+
+pub fn f(new: fn()) {
+    new();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
new file mode 100644
index 00000000000..9e5e299c336
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+#![allow(
+    unused_variables,
+    clippy::blacklisted_name,
+    clippy::needless_pass_by_value,
+    dead_code
+)]
+
+/// This should not compile-fail with:
+///
+///      error[E0277]: the trait bound `T: Foo` is not satisfied
+// See rust-lang/rust-clippy#2760.
+
+trait Foo {
+    type Bar;
+}
+
+struct Baz<T: Foo> {
+    bar: T::Bar,
+}
+
+fn take<T: Foo>(baz: Baz<T>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.rs b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
new file mode 100644
index 00000000000..47f8e3b18ee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
@@ -0,0 +1,29 @@
+// run-pass
+
+use std::collections::HashSet;
+
+// See rust-lang/rust-clippy#2774.
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Bar {
+    foo: Foo,
+}
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Foo {}
+
+#[allow(clippy::implicit_hasher)]
+// This should not cause a "cannot relate bound region" ICE.
+pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(bars.iter().map(|b| &b.foo));
+}
+
+#[allow(clippy::implicit_hasher)]
+// Also, this should not cause a "cannot relate bound region" ICE.
+pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(bars.iter().map(|b| &b.foo));
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2862.rs b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
new file mode 100644
index 00000000000..47324ce1831
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2862
+
+pub trait FooMap {
+    fn map<B, F: Fn() -> B>(&self, f: F) -> B;
+}
+
+impl FooMap for bool {
+    fn map<B, F: Fn() -> B>(&self, f: F) -> B {
+        f()
+    }
+}
+
+fn main() {
+    let a = true;
+    a.map(|| false);
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2865.rs b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
new file mode 100644
index 00000000000..c4f6c0fed68
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+#[allow(dead_code)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
+
+struct Ice {
+    size: String,
+}
+
+impl<'a> From<String> for Ice {
+    fn from(_: String) -> Self {
+        let text = || "iceberg".to_string();
+        Self { size: text() }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3151.rs b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
new file mode 100644
index 00000000000..ffad2d06b56
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
+
+#[derive(Clone)]
+pub struct HashMap<V, S> {
+    hash_builder: S,
+    table: RawTable<V>,
+}
+
+#[derive(Clone)]
+pub struct RawTable<V> {
+    size: usize,
+    val: V,
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
new file mode 100644
index 00000000000..95c7dff9be3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+#![warn(clippy::all)]
+#![allow(clippy::blacklisted_name)]
+#![allow(unused)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
+
+enum Foo {
+    Bar,
+    Baz,
+}
+
+fn bar(foo: Foo) {
+    macro_rules! baz {
+        () => {
+            if let Foo::Bar = foo {}
+        };
+    }
+
+    baz!();
+    baz!();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.rs b/src/tools/clippy/tests/ui/crashes/ice-360.rs
new file mode 100644
index 00000000000..6555c19ca6a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-360.rs
@@ -0,0 +1,12 @@
+fn main() {}
+
+fn no_panic<T>(slice: &[T]) {
+    let mut iter = slice.iter();
+    loop {
+        let _ = match iter.next() {
+            Some(ele) => ele,
+            None => break,
+        };
+        loop {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.stderr b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
new file mode 100644
index 00000000000..84e31eaf2e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
@@ -0,0 +1,24 @@
+error: this loop could be written as a `while let` loop
+  --> $DIR/ice-360.rs:5:5
+   |
+LL | /     loop {
+LL | |         let _ = match iter.next() {
+LL | |             Some(ele) => ele,
+LL | |             None => break,
+LL | |         };
+LL | |         loop {}
+LL | |     }
+   | |_____^ help: try: `while let Some(ele) = iter.next() { .. }`
+   |
+   = note: `-D clippy::while-let-loop` implied by `-D warnings`
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/ice-360.rs:10:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::empty-loop` implied by `-D warnings`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.rs b/src/tools/clippy/tests/ui/crashes/ice-3717.rs
new file mode 100644
index 00000000000..f50714643fd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3717.rs
@@ -0,0 +1,10 @@
+#![deny(clippy::implicit_hasher)]
+
+use std::collections::HashSet;
+
+fn main() {}
+
+pub fn ice_3717(_: &HashSet<usize>) {
+    let _ = [0u8; 0];
+    let _: HashSet<usize> = HashSet::new();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
new file mode 100644
index 00000000000..296c95abb96
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
@@ -0,0 +1,22 @@
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> $DIR/ice-3717.rs:7:21
+   |
+LL | pub fn ice_3717(_: &HashSet<usize>) {
+   |                     ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/ice-3717.rs:1:9
+   |
+LL | #![deny(clippy::implicit_hasher)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+help: consider adding a type parameter
+   |
+LL | pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |     let _: HashSet<usize> = HashSet::default();
+   |                             ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3741.rs b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
new file mode 100644
index 00000000000..74b9c9c86c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
@@ -0,0 +1,12 @@
+// aux-build:proc_macro_crash.rs
+// run-pass
+
+#![feature(proc_macro_hygiene)]
+#![warn(clippy::suspicious_else_formatting)]
+
+extern crate proc_macro_crash;
+use proc_macro_crash::macro_test;
+
+fn main() {
+    macro_test!(2);
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3747.rs b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
new file mode 100644
index 00000000000..d0b44ebafee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/3747
+
+macro_rules! a {
+    ( $pub:tt $($attr:tt)* ) => {
+        $($attr)* $pub fn say_hello() {}
+    };
+}
+
+macro_rules! b {
+    () => {
+        a! { pub }
+    };
+}
+
+b! {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3891.rs b/src/tools/clippy/tests/ui/crashes/ice-3891.rs
new file mode 100644
index 00000000000..05c5134c845
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3891.rs
@@ -0,0 +1,3 @@
+fn main() {
+    1x;
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3891.stderr b/src/tools/clippy/tests/ui/crashes/ice-3891.stderr
new file mode 100644
index 00000000000..5a285b0e714
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3891.stderr
@@ -0,0 +1,10 @@
+error: invalid suffix `x` for integer literal
+  --> $DIR/ice-3891.rs:2:5
+   |
+LL |     1x;
+   |     ^^ invalid suffix `x`
+   |
+   = help: the suffix must be one of the integral types (`u32`, `isize`, etc)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4121.rs b/src/tools/clippy/tests/ui/crashes/ice-4121.rs
new file mode 100644
index 00000000000..e1a142fdcb6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4121.rs
@@ -0,0 +1,13 @@
+use std::mem;
+
+pub struct Foo<A, B>(A, B);
+
+impl<A, B> Foo<A, B> {
+    const HOST_SIZE: usize = mem::size_of::<B>();
+
+    pub fn crash() -> bool {
+        Self::HOST_SIZE == 0
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4545.rs b/src/tools/clippy/tests/ui/crashes/ice-4545.rs
new file mode 100644
index 00000000000..d9c9c2096d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4545.rs
@@ -0,0 +1,14 @@
+fn repro() {
+    trait Foo {
+        type Bar;
+    }
+
+    #[allow(dead_code)]
+    struct Baz<T: Foo> {
+        field: T::Bar,
+    }
+}
+
+fn main() {
+    repro();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4579.rs b/src/tools/clippy/tests/ui/crashes/ice-4579.rs
new file mode 100644
index 00000000000..2e7e279f847
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4579.rs
@@ -0,0 +1,13 @@
+#![allow(clippy::single_match)]
+
+use std::ptr;
+
+fn main() {
+    match Some(0_usize) {
+        Some(_) => {
+            let s = "012345";
+            unsafe { ptr::read(s.as_ptr().offset(1) as *const [u8; 5]) };
+        },
+        _ => (),
+    };
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4671.rs b/src/tools/clippy/tests/ui/crashes/ice-4671.rs
new file mode 100644
index 00000000000..64e8e776941
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4671.rs
@@ -0,0 +1,21 @@
+#![warn(clippy::use_self)]
+
+#[macro_use]
+#[path = "auxiliary/use_self_macro.rs"]
+mod use_self_macro;
+
+struct Foo {
+    a: u32,
+}
+
+use_self! {
+    impl Foo {
+        fn func(&self) {
+            [fields(
+                a
+            )]
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4727.rs b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
new file mode 100644
index 00000000000..cdb59caec67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+#![warn(clippy::use_self)]
+
+#[path = "auxiliary/ice-4727-aux.rs"]
+mod aux;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4760.rs b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
new file mode 100644
index 00000000000..ead67d5ed1b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
@@ -0,0 +1,10 @@
+// run-pass
+const COUNT: usize = 2;
+struct Thing;
+trait Dummy {}
+
+const _: () = {
+    impl Dummy for Thing where [i32; COUNT]: Sized {}
+};
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4775.rs b/src/tools/clippy/tests/ui/crashes/ice-4775.rs
new file mode 100644
index 00000000000..31e53e846d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4775.rs
@@ -0,0 +1,14 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+pub struct ArrayWrapper<const N: usize>([usize; N]);
+
+impl<const N: usize> ArrayWrapper<{ N }> {
+    pub fn ice(&self) {
+        for i in self.0.iter() {
+            println!("{}", i);
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4968.rs b/src/tools/clippy/tests/ui/crashes/ice-4968.rs
new file mode 100644
index 00000000000..3822f174598
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-4968.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+// Test for https://github.com/rust-lang/rust-clippy/issues/4968
+
+#![warn(clippy::unsound_collection_transmute)]
+
+trait Trait {
+    type Assoc;
+}
+
+use std::mem::{self, ManuallyDrop};
+
+#[allow(unused)]
+fn func<T: Trait>(slice: Vec<T::Assoc>) {
+    unsafe {
+        let _: Vec<ManuallyDrop<T::Assoc>> = mem::transmute(slice);
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
new file mode 100644
index 00000000000..1b20c9defac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
@@ -0,0 +1,7 @@
+// edition:2018
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
+
+pub async fn bar<'a, T: 'a>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5223.rs b/src/tools/clippy/tests/ui/crashes/ice-5223.rs
new file mode 100644
index 00000000000..9bb2e227fc1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5223.rs
@@ -0,0 +1,18 @@
+// Regression test for #5233
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![warn(clippy::indexing_slicing, clippy::iter_cloned_collect)]
+
+pub struct KotomineArray<T, const N: usize> {
+    arr: [T; N],
+}
+
+impl<T: std::clone::Clone, const N: usize> KotomineArray<T, N> {
+    pub fn ice(self) {
+        let _ = self.arr[..];
+        let _ = self.arr.iter().cloned().collect::<Vec<_>>();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
new file mode 100644
index 00000000000..989eb6d4485
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
@@ -0,0 +1,9 @@
+// Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562
+
+#![feature(generators, generator_trait)]
+
+fn main() {
+    let _ = || {
+        yield;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5497.rs b/src/tools/clippy/tests/ui/crashes/ice-5497.rs
new file mode 100644
index 00000000000..0769bce5fc8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-5497.rs
@@ -0,0 +1,11 @@
+// reduced from rustc issue-69020-assoc-const-arith-overflow.rs
+pub fn main() {}
+
+pub trait Foo {
+    const OOB: i32;
+}
+
+impl<T: Foo> Foo for Vec<T> {
+    const OOB: i32 = [1][1] + T::OOB;
+    //~^ ERROR operation will panic
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs
new file mode 100644
index 00000000000..b06df83d51a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+#![deny(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/700
+
+fn core() {}
+
+fn main() {
+    core();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
new file mode 100644
index 00000000000..e02eb28ab86
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![deny(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1336
+
+#[allow(dead_code)]
+struct Foo;
+
+impl Iterator for Foo {
+    type Item = ();
+
+    fn next(&mut self) -> Option<()> {
+        let _ = self.len() == 0;
+        unimplemented!()
+    }
+}
+
+impl ExactSizeIterator for Foo {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
new file mode 100644
index 00000000000..4ef992b05e7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+#![allow(clippy::comparison_chain)]
+#![deny(clippy::if_same_then_else)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2426
+
+fn main() {}
+
+pub fn foo(a: i32, b: i32) -> Option<&'static str> {
+    if a == b {
+        None
+    } else if a > b {
+        Some("a pfeil b")
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/inherent_impl.rs b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs
new file mode 100644
index 00000000000..aeb27b5ba8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs
@@ -0,0 +1,26 @@
+#![deny(clippy::multiple_inherent_impl)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/4578
+
+macro_rules! impl_foo {
+    ($struct:ident) => {
+        impl $struct {
+            fn foo() {}
+        }
+    };
+}
+
+macro_rules! impl_bar {
+    ($struct:ident) => {
+        impl $struct {
+            fn bar() {}
+        }
+    };
+}
+
+struct MyStruct;
+
+impl_foo!(MyStruct);
+impl_bar!(MyStruct);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/issue-825.rs b/src/tools/clippy/tests/ui/crashes/issue-825.rs
new file mode 100644
index 00000000000..3d4a88ab3c4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/issue-825.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+#![allow(warnings)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/825
+
+// this should compile in a reasonable amount of time
+fn rust_type_id(name: &str) {
+    if "bool" == &name[..]
+        || "uint" == &name[..]
+        || "u8" == &name[..]
+        || "u16" == &name[..]
+        || "u32" == &name[..]
+        || "f32" == &name[..]
+        || "f64" == &name[..]
+        || "i8" == &name[..]
+        || "i16" == &name[..]
+        || "i32" == &name[..]
+        || "i64" == &name[..]
+        || "Self" == &name[..]
+        || "str" == &name[..]
+    {
+        unreachable!();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
new file mode 100644
index 00000000000..c4acd5cda1b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+#![allow(dead_code)]
+
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
+pub fn loop_on_block_condition(u: &mut isize) {
+    while { *u < 0 } {
+        *u += 1;
+    }
+}
+
+/// https://github.com/rust-lang/rust-clippy/issues/2584
+fn loop_with_unsafe_condition(ptr: *const u8) {
+    let mut len = 0;
+    while unsafe { *ptr.offset(len) } != 0 {
+        len += 1;
+    }
+}
+
+/// https://github.com/rust-lang/rust-clippy/issues/2710
+static mut RUNNING: bool = true;
+fn loop_on_static_condition() {
+    unsafe {
+        while RUNNING {
+            RUNNING = false;
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
new file mode 100644
index 00000000000..848f0ea52ca
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+#![deny(clippy::match_same_arms)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2427
+
+const PRICE_OF_SWEETS: u32 = 5;
+const PRICE_OF_KINDNESS: u32 = 0;
+const PRICE_OF_DRINKS: u32 = 5;
+
+pub fn price(thing: &str) -> u32 {
+    match thing {
+        "rolo" => PRICE_OF_SWEETS,
+        "advice" => PRICE_OF_KINDNESS,
+        "juice" => PRICE_OF_DRINKS,
+        _ => panic!(),
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
new file mode 100644
index 00000000000..d8fbaa54146
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+#![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
+#![allow(dead_code)]
+
+// FIXME: compiletest + extern crates doesn't work together. To make this test work, it would need
+// the following three lines and the lazy_static crate.
+//
+//     #[macro_use]
+//     extern crate lazy_static;
+//     use std::collections::HashMap;
+
+/// ensure that we don't suggest `is_nan` and `is_null` inside constants
+/// FIXME: once const fn is stable, suggest these functions again in constants
+
+const BAA: *const i32 = 0 as *const i32;
+static mut BAR: *const i32 = BAA;
+static mut FOO: *const i32 = 0 as *const i32;
+static mut BUH: bool = 42.0 < f32::NAN;
+
+#[allow(unused_variables, unused_mut)]
+fn main() {
+    /*
+    lazy_static! {
+        static ref MUT_MAP : HashMap<usize, &'static str> = {
+            let mut m = HashMap::new();
+            m.insert(0, "zero");
+            m
+        };
+        static ref MUT_COUNT : usize = MUT_MAP.len();
+    }
+    assert_eq!(*MUT_COUNT, 1);
+    */
+    // FIXME: don't lint in array length, requires `check_body`
+    //let _ = [""; (42.0 < f32::NAN) as usize];
+}
diff --git a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
new file mode 100644
index 00000000000..48507efe1e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+#[deny(clippy::all)]
+#[derive(Debug)]
+pub enum Error {
+    Type(&'static str),
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
new file mode 100644
index 00000000000..bd1fa4a0b1e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+#![deny(clippy::needless_lifetimes)]
+#![allow(dead_code)]
+
+trait Foo {}
+
+struct Bar {}
+
+struct Baz<'a> {
+    bar: &'a Bar,
+}
+
+impl<'a> Foo for Baz<'a> {}
+
+impl Bar {
+    fn baz<'a>(&'a self) -> impl Foo + 'a {
+        Baz { bar: self }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
new file mode 100644
index 00000000000..f79d9ab6460
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+#[macro_use]
+extern crate clippy_mini_macro_test;
+
+#[deny(warnings)]
+fn main() {
+    let x = Foo;
+    println!("{:?}", x);
+}
+
+#[derive(ClippyMiniMacroTest, Debug)]
+struct Foo;
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
new file mode 100644
index 00000000000..623ae51f9f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+#![allow(clippy::blacklisted_name)]
+
+pub fn foo(bar: *const u8) {
+    println!("{:#p}", bar);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs
new file mode 100644
index 00000000000..f2153efc388
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/returns.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1346
+
+#[deny(warnings)]
+fn cfg_return() -> i32 {
+    #[cfg(unix)]
+    return 1;
+    #[cfg(not(unix))]
+    return 2;
+}
+
+#[deny(warnings)]
+fn cfg_let_and_return() -> i32 {
+    #[cfg(unix)]
+    let x = 1;
+    #[cfg(not(unix))]
+    let x = 2;
+    x
+}
+
+fn main() {
+    cfg_return();
+    cfg_let_and_return();
+}
diff --git a/src/tools/clippy/tests/ui/crashes/shadow.rs b/src/tools/clippy/tests/ui/crashes/shadow.rs
new file mode 100644
index 00000000000..843e8ef64dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/shadow.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let x: [i32; {
+        let u = 2;
+        4
+    }] = [2; { 4 }];
+}
diff --git a/src/tools/clippy/tests/ui/crashes/single-match-else.rs b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
new file mode 100644
index 00000000000..3a4bbe310cc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+#![warn(clippy::single_match_else)]
+
+//! Test for https://github.com/rust-lang/rust-clippy/issues/1588
+
+fn main() {
+    let n = match (42, 43) {
+        (42, n) => n,
+        _ => panic!("typeck error"),
+    };
+    assert_eq!(n, 43);
+}
diff --git a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
new file mode 100644
index 00000000000..2bb95c18a39
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+#![feature(trivial_bounds)]
+#![allow(unused, trivial_bounds)]
+
+fn test_trivial_bounds()
+where
+    i32: Iterator,
+{
+    for _ in 2i32 {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
new file mode 100644
index 00000000000..265017c51d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![allow(clippy::useless_attribute)] //issue #2910
+
+#[macro_use]
+extern crate serde_derive;
+
+/// Tests that we do not lint for unused underscores in a `MacroAttribute`
+/// expansion
+#[deny(clippy::used_underscore_binding)]
+#[derive(Deserialize)]
+struct MacroAttributesTest {
+    _foo: u32,
+}
+
+#[test]
+fn macro_attributes_test() {
+    let _ = MacroAttributesTest { _foo: 0 };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/whitelist/clippy.toml b/src/tools/clippy/tests/ui/crashes/whitelist/clippy.toml
new file mode 100644
index 00000000000..9f87de20baf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/whitelist/clippy.toml
@@ -0,0 +1,3 @@
+# this is ignored by Clippy, but allowed for other tools like clippy-service
+[third-party]
+clippy-feature = "nightly"
diff --git a/src/tools/clippy/tests/ui/crashes/whitelist/conf_whitelisted.rs b/src/tools/clippy/tests/ui/crashes/whitelist/conf_whitelisted.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/whitelist/conf_whitelisted.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs
new file mode 100644
index 00000000000..995787c5336
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs
@@ -0,0 +1,12 @@
+// ignore-macos
+// ignore-windows
+
+#![feature(main)]
+
+#[warn(clippy::main_recursion)]
+#[allow(unconditional_recursion)]
+#[main]
+fn a() {
+    println!("Hello, World!");
+    a();
+}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr
new file mode 100644
index 00000000000..f52fc949f6c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr
@@ -0,0 +1,11 @@
+error: recursing into entrypoint `a`
+  --> $DIR/entrypoint_recursion.rs:11:5
+   |
+LL |     a();
+   |     ^
+   |
+   = note: `-D clippy::main-recursion` implied by `-D warnings`
+   = help: consider using another function for this recursion
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
new file mode 100644
index 00000000000..25b1417be97
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs
@@ -0,0 +1,33 @@
+// ignore-macos
+// ignore-windows
+
+#![feature(lang_items, link_args, start, libc)]
+#![link_args = "-nostartfiles"]
+#![no_std]
+
+use core::panic::PanicInfo;
+use core::sync::atomic::{AtomicUsize, Ordering};
+
+static N: AtomicUsize = AtomicUsize::new(0);
+
+#[warn(clippy::main_recursion)]
+#[start]
+fn main(argc: isize, argv: *const *const u8) -> isize {
+    let x = N.load(Ordering::Relaxed);
+    N.store(x + 1, Ordering::Relaxed);
+
+    if x < 3 {
+        main(argc, argv);
+    }
+
+    0
+}
+
+#[allow(clippy::empty_loop)]
+#[panic_handler]
+fn panic(_info: &PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs
new file mode 100644
index 00000000000..89ff6609934
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs
@@ -0,0 +1,6 @@
+#[warn(clippy::main_recursion)]
+#[allow(unconditional_recursion)]
+fn main() {
+    println!("Hello, World!");
+    main();
+}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr
new file mode 100644
index 00000000000..0a260f9d230
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr
@@ -0,0 +1,11 @@
+error: recursing into entrypoint `main`
+  --> $DIR/std_main_recursion.rs:5:5
+   |
+LL |     main();
+   |     ^^^^
+   |
+   = note: `-D clippy::main-recursion` implied by `-D warnings`
+   = help: consider using another function for this recursion
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/cstring.rs b/src/tools/clippy/tests/ui/cstring.rs
new file mode 100644
index 00000000000..6cdd6b4ff6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cstring.rs
@@ -0,0 +1,24 @@
+#![deny(clippy::temporary_cstring_as_ptr)]
+
+fn main() {}
+
+fn temporary_cstring() {
+    use std::ffi::CString;
+
+    CString::new("foo").unwrap().as_ptr();
+    CString::new("foo").expect("dummy").as_ptr();
+}
+
+mod issue4375 {
+    use std::ffi::CString;
+    use std::os::raw::c_char;
+
+    extern "C" {
+        fn foo(data: *const c_char);
+    }
+
+    pub fn bar(v: &[u8]) {
+        let cstr = CString::new(v);
+        unsafe { foo(cstr.unwrap().as_ptr()) }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cstring.stderr b/src/tools/clippy/tests/ui/cstring.stderr
new file mode 100644
index 00000000000..87cb29be577
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cstring.stderr
@@ -0,0 +1,46 @@
+error: you are getting the inner pointer of a temporary `CString`
+  --> $DIR/cstring.rs:8:5
+   |
+LL |     CString::new("foo").unwrap().as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/cstring.rs:1:9
+   |
+LL | #![deny(clippy::temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: that pointer will be invalid outside this expression
+help: assign the `CString` to a variable to extend its lifetime
+  --> $DIR/cstring.rs:8:5
+   |
+LL |     CString::new("foo").unwrap().as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you are getting the inner pointer of a temporary `CString`
+  --> $DIR/cstring.rs:9:5
+   |
+LL |     CString::new("foo").expect("dummy").as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: that pointer will be invalid outside this expression
+help: assign the `CString` to a variable to extend its lifetime
+  --> $DIR/cstring.rs:9:5
+   |
+LL |     CString::new("foo").expect("dummy").as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you are getting the inner pointer of a temporary `CString`
+  --> $DIR/cstring.rs:22:22
+   |
+LL |         unsafe { foo(cstr.unwrap().as_ptr()) }
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: that pointer will be invalid outside this expression
+help: assign the `CString` to a variable to extend its lifetime
+  --> $DIR/cstring.rs:22:22
+   |
+LL |         unsafe { foo(cstr.unwrap().as_ptr()) }
+   |                      ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/custom_ice_message.rs b/src/tools/clippy/tests/ui/custom_ice_message.rs
new file mode 100644
index 00000000000..5b30c9d5721
--- /dev/null
+++ b/src/tools/clippy/tests/ui/custom_ice_message.rs
@@ -0,0 +1,10 @@
+// rustc-env:RUST_BACKTRACE=0
+// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
+// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs"
+// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
+
+#![deny(clippy::internal)]
+
+fn it_looks_like_you_are_trying_to_kill_clippy() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr
new file mode 100644
index 00000000000..a9a65a38c10
--- /dev/null
+++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr
@@ -0,0 +1,11 @@
+thread 'rustc' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints.rs
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+error: internal compiler error: unexpected panic
+
+note: the compiler unexpectedly panicked. this is a bug.
+
+note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
+
+note: Clippy version: foo
+
diff --git a/src/tools/clippy/tests/ui/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro.rs
new file mode 100644
index 00000000000..d2df7fbd3e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dbg_macro.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::dbg_macro)]
+
+fn foo(n: u32) -> u32 {
+    if let Some(n) = dbg!(n.checked_sub(4)) {
+        n
+    } else {
+        n
+    }
+}
+
+fn factorial(n: u32) -> u32 {
+    if dbg!(n <= 1) {
+        dbg!(1)
+    } else {
+        dbg!(n * factorial(n - 1))
+    }
+}
+
+fn main() {
+    dbg!(42);
+    dbg!(dbg!(dbg!(42)));
+    foo(3) + dbg!(factorial(4));
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr
new file mode 100644
index 00000000000..b8aafe96678
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dbg_macro.stderr
@@ -0,0 +1,80 @@
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:4:22
+   |
+LL |     if let Some(n) = dbg!(n.checked_sub(4)) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::dbg-macro` implied by `-D warnings`
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if let Some(n) = n.checked_sub(4) {
+   |                      ^^^^^^^^^^^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:12:8
+   |
+LL |     if dbg!(n <= 1) {
+   |        ^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if n <= 1 {
+   |        ^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:13:9
+   |
+LL |         dbg!(1)
+   |         ^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |         1
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:15:9
+   |
+LL |         dbg!(n * factorial(n - 1))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |         n * factorial(n - 1)
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:20:5
+   |
+LL |     dbg!(42);
+   |     ^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     42;
+   |     ^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:21:5
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     dbg!(dbg!(42));
+   |     ^^^^^^^^^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:22:14
+   |
+LL |     foo(3) + dbg!(factorial(4));
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     foo(3) + factorial(4);
+   |              ^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs
new file mode 100644
index 00000000000..477a47118d4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs
@@ -0,0 +1,133 @@
+// compile-flags: --edition=2018
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+#![warn(clippy::debug_assert_with_mut_call)]
+#![allow(clippy::redundant_closure_call)]
+
+struct S;
+
+impl S {
+    fn bool_self_ref(&self) -> bool { false }
+    fn bool_self_mut(&mut self) -> bool { false }
+    fn bool_self_ref_arg_ref(&self, _: &u32) -> bool { false }
+    fn bool_self_ref_arg_mut(&self, _: &mut u32) -> bool { false }
+    fn bool_self_mut_arg_ref(&mut self, _: &u32) -> bool { false }
+    fn bool_self_mut_arg_mut(&mut self, _: &mut u32) -> bool { false }
+
+    fn u32_self_ref(&self) -> u32 { 0 }
+    fn u32_self_mut(&mut self) -> u32 { 0 }
+    fn u32_self_ref_arg_ref(&self, _: &u32) -> u32 { 0 }
+    fn u32_self_ref_arg_mut(&self, _: &mut u32) -> u32 { 0 }
+    fn u32_self_mut_arg_ref(&mut self, _: &u32) -> u32 { 0 }
+    fn u32_self_mut_arg_mut(&mut self, _: &mut u32) -> u32 { 0 }
+}
+
+fn bool_ref(_: &u32) -> bool { false }
+fn bool_mut(_: &mut u32) -> bool { false }
+fn u32_ref(_: &u32) -> u32 { 0 }
+fn u32_mut(_: &mut u32) -> u32 { 0 }
+
+fn func_non_mutable() {
+    debug_assert!(bool_ref(&3));
+    debug_assert!(!bool_ref(&3));
+
+    debug_assert_eq!(0, u32_ref(&3));
+    debug_assert_eq!(u32_ref(&3), 0);
+
+    debug_assert_ne!(1, u32_ref(&3));
+    debug_assert_ne!(u32_ref(&3), 1);
+}
+
+fn func_mutable() {
+    debug_assert!(bool_mut(&mut 3));
+    debug_assert!(!bool_mut(&mut 3));
+
+    debug_assert_eq!(0, u32_mut(&mut 3));
+    debug_assert_eq!(u32_mut(&mut 3), 0);
+
+    debug_assert_ne!(1, u32_mut(&mut 3));
+    debug_assert_ne!(u32_mut(&mut 3), 1);
+}
+
+fn method_non_mutable() {
+    debug_assert!(S.bool_self_ref());
+    debug_assert!(S.bool_self_ref_arg_ref(&3));
+
+    debug_assert_eq!(S.u32_self_ref(), 0);
+    debug_assert_eq!(S.u32_self_ref_arg_ref(&3), 0);
+
+    debug_assert_ne!(S.u32_self_ref(), 1);
+    debug_assert_ne!(S.u32_self_ref_arg_ref(&3), 1);
+}
+
+fn method_mutable() {
+    debug_assert!(S.bool_self_mut());
+    debug_assert!(!S.bool_self_mut());
+    debug_assert!(S.bool_self_ref_arg_mut(&mut 3));
+    debug_assert!(S.bool_self_mut_arg_ref(&3));
+    debug_assert!(S.bool_self_mut_arg_mut(&mut 3));
+
+    debug_assert_eq!(S.u32_self_mut(), 0);
+    debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0);
+    debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0);
+    debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0);
+
+    debug_assert_ne!(S.u32_self_mut(), 1);
+    debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1);
+    debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1);
+    debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1);
+}
+
+fn misc() {
+    // with variable
+    let mut v: Vec<u32> = vec![1, 2, 3, 4];
+    debug_assert_eq!(v.get(0), Some(&1));
+    debug_assert_ne!(v[0], 2);
+    debug_assert_eq!(v.pop(), Some(1));
+    debug_assert_ne!(Some(3), v.pop());
+
+    let a = &mut 3;
+    debug_assert!(bool_mut(a));
+
+    // nested
+    debug_assert!(!(bool_ref(&u32_mut(&mut 3))));
+
+    // chained
+    debug_assert_eq!(v.pop().unwrap(), 3);
+
+    // format args
+    debug_assert!(bool_ref(&3), "w/o format");
+    debug_assert!(bool_mut(&mut 3), "w/o format");
+    debug_assert!(bool_ref(&3), "{} format", "w/");
+    debug_assert!(bool_mut(&mut 3), "{} format", "w/");
+
+    // sub block
+    let mut x = 42_u32;
+    debug_assert!({
+        bool_mut(&mut x);
+        x > 10
+    });
+
+    // closures
+    debug_assert!((|| {
+        let mut x = 42;
+        bool_mut(&mut x);
+        x > 10
+    })());
+}
+
+async fn debug_await() {
+    debug_assert!(async {
+        true
+    }.await);
+}
+
+fn main() {
+    func_non_mutable();
+    func_mutable();
+    method_non_mutable();
+    method_mutable();
+
+    misc();
+    debug_await();
+}
diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr
new file mode 100644
index 00000000000..a2ca71b57a6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr
@@ -0,0 +1,172 @@
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:42:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::debug-assert-with-mut-call` implied by `-D warnings`
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:43:20
+   |
+LL |     debug_assert!(!bool_mut(&mut 3));
+   |                    ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:45:25
+   |
+LL |     debug_assert_eq!(0, u32_mut(&mut 3));
+   |                         ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:46:22
+   |
+LL |     debug_assert_eq!(u32_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:48:25
+   |
+LL |     debug_assert_ne!(1, u32_mut(&mut 3));
+   |                         ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:49:22
+   |
+LL |     debug_assert_ne!(u32_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:64:19
+   |
+LL |     debug_assert!(S.bool_self_mut());
+   |                   ^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:65:20
+   |
+LL |     debug_assert!(!S.bool_self_mut());
+   |                    ^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:66:19
+   |
+LL |     debug_assert!(S.bool_self_ref_arg_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:67:19
+   |
+LL |     debug_assert!(S.bool_self_mut_arg_ref(&3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:68:19
+   |
+LL |     debug_assert!(S.bool_self_mut_arg_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:70:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut(), 0);
+   |                      ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:71:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:72:22
+   |
+LL |     debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:73:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:75:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut(), 1);
+   |                      ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:76:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:77:22
+   |
+LL |     debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:78:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:86:22
+   |
+LL |     debug_assert_eq!(v.pop(), Some(1));
+   |                      ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:87:31
+   |
+LL |     debug_assert_ne!(Some(3), v.pop());
+   |                               ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:90:19
+   |
+LL |     debug_assert!(bool_mut(a));
+   |                   ^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:93:31
+   |
+LL |     debug_assert!(!(bool_ref(&u32_mut(&mut 3))));
+   |                               ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:96:22
+   |
+LL |     debug_assert_eq!(v.pop().unwrap(), 3);
+   |                      ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:100:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3), "w/o format");
+   |                   ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:102:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3), "{} format", "w/");
+   |                   ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:107:9
+   |
+LL |         bool_mut(&mut x);
+   |         ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:114:9
+   |
+LL |         bool_mut(&mut x);
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to 28 previous errors
+
diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.fixed b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed
new file mode 100644
index 00000000000..de391465125
--- /dev/null
+++ b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+
+#[warn(clippy::decimal_literal_representation)]
+#[allow(unused_variables)]
+#[rustfmt::skip]
+fn main() {
+    let good = (       // Hex:
+        127,           // 0x7F
+        256,           // 0x100
+        511,           // 0x1FF
+        2048,          // 0x800
+        4090,          // 0xFFA
+        16_371,        // 0x3FF3
+        61_683,        // 0xF0F3
+        2_131_750_925, // 0x7F0F_F00D
+    );
+    let bad = (        // Hex:
+        0x8005,        // 0x8005
+        0xFF00,        // 0xFF00
+        0x7F0F_F00F, // 0x7F0F_F00F
+        0x7FFF_FFFF, // 0x7FFF_FFFF
+        #[allow(overflowing_literals)]
+        0xF0F0_F0F0, // 0xF0F0_F0F0
+        0x8005_usize,   // 0x8005_usize
+        0x7F0F_F00F_isize, // 0x7F0F_F00F_isize
+    );
+}
diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.rs b/src/tools/clippy/tests/ui/decimal_literal_representation.rs
new file mode 100644
index 00000000000..55d07698e7e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/decimal_literal_representation.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+
+#[warn(clippy::decimal_literal_representation)]
+#[allow(unused_variables)]
+#[rustfmt::skip]
+fn main() {
+    let good = (       // Hex:
+        127,           // 0x7F
+        256,           // 0x100
+        511,           // 0x1FF
+        2048,          // 0x800
+        4090,          // 0xFFA
+        16_371,        // 0x3FF3
+        61_683,        // 0xF0F3
+        2_131_750_925, // 0x7F0F_F00D
+    );
+    let bad = (        // Hex:
+        32_773,        // 0x8005
+        65_280,        // 0xFF00
+        2_131_750_927, // 0x7F0F_F00F
+        2_147_483_647, // 0x7FFF_FFFF
+        #[allow(overflowing_literals)]
+        4_042_322_160, // 0xF0F0_F0F0
+        32_773usize,   // 0x8005_usize
+        2_131_750_927isize, // 0x7F0F_F00F_isize
+    );
+}
diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.stderr b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr
new file mode 100644
index 00000000000..8d50c8f83db
--- /dev/null
+++ b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr
@@ -0,0 +1,46 @@
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:18:9
+   |
+LL |         32_773,        // 0x8005
+   |         ^^^^^^ help: consider: `0x8005`
+   |
+   = note: `-D clippy::decimal-literal-representation` implied by `-D warnings`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:19:9
+   |
+LL |         65_280,        // 0xFF00
+   |         ^^^^^^ help: consider: `0xFF00`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:20:9
+   |
+LL |         2_131_750_927, // 0x7F0F_F00F
+   |         ^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:21:9
+   |
+LL |         2_147_483_647, // 0x7FFF_FFFF
+   |         ^^^^^^^^^^^^^ help: consider: `0x7FFF_FFFF`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:23:9
+   |
+LL |         4_042_322_160, // 0xF0F0_F0F0
+   |         ^^^^^^^^^^^^^ help: consider: `0xF0F0_F0F0`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:24:9
+   |
+LL |         32_773usize,   // 0x8005_usize
+   |         ^^^^^^^^^^^ help: consider: `0x8005_usize`
+
+error: integer literal has a better hexadecimal representation
+  --> $DIR/decimal_literal_representation.rs:25:9
+   |
+LL |         2_131_750_927isize, // 0x7F0F_F00F_isize
+   |         ^^^^^^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F_isize`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
new file mode 100644
index 00000000000..b4003ed8932
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
@@ -0,0 +1,93 @@
+#![warn(clippy::declare_interior_mutable_const)]
+
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::fmt::Display;
+use std::sync::atomic::AtomicUsize;
+use std::sync::Once;
+
+const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
+const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+//~^ ERROR interior mutable
+
+macro_rules! declare_const {
+    ($name:ident: $ty:ty = $e:expr) => {
+        const $name: $ty = $e;
+    };
+}
+declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
+
+// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
+
+const INTEGER: u8 = 8;
+const STRING: String = String::new();
+const STR: &str = "012345";
+const COW: Cow<str> = Cow::Borrowed("abcdef");
+//^ note: a const item of Cow is used in the `postgres` package.
+
+const NO_ANN: &dyn Display = &70;
+
+static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
+//^ there should be no lints on this line
+
+#[allow(clippy::declare_interior_mutable_const)]
+const ONCE_INIT: Once = Once::new();
+
+trait Trait<T>: Copy {
+    type NonCopyType;
+
+    const ATOMIC: AtomicUsize; //~ ERROR interior mutable
+    const INTEGER: u64;
+    const STRING: String;
+    const SELF: Self; // (no error)
+    const INPUT: T;
+    //~^ ERROR interior mutable
+    //~| HELP consider requiring `T` to be `Copy`
+    const ASSOC: Self::NonCopyType;
+    //~^ ERROR interior mutable
+    //~| HELP consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+
+    const AN_INPUT: T = Self::INPUT;
+    //~^ ERROR interior mutable
+    //~| ERROR consider requiring `T` to be `Copy`
+    declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
+}
+
+trait Trait2 {
+    type CopyType: Copy;
+
+    const SELF_2: Self;
+    //~^ ERROR interior mutable
+    //~| HELP consider requiring `Self` to be `Copy`
+    const ASSOC_2: Self::CopyType; // (no error)
+}
+
+// we don't lint impl of traits, because an impl has no power to change the interface.
+impl Trait<u32> for u64 {
+    type NonCopyType = u16;
+
+    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+    const INTEGER: u64 = 10;
+    const STRING: String = String::new();
+    const SELF: Self = 11;
+    const INPUT: u32 = 12;
+    const ASSOC: Self::NonCopyType = 13;
+}
+
+struct Local<T, U>(T, U);
+
+impl<T: Trait2 + Trait<u32>, U: Trait2> Local<T, U> {
+    const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
+    const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
+    const T_SELF: T = T::SELF_2;
+    const U_SELF: U = U::SELF_2;
+    //~^ ERROR interior mutable
+    //~| HELP consider requiring `U` to be `Copy`
+    const T_ASSOC: T::NonCopyType = T::ASSOC;
+    //~^ ERROR interior mutable
+    //~| HELP consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
+    const U_ASSOC: U::CopyType = U::ASSOC_2;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
new file mode 100644
index 00000000000..6a9a57361f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
@@ -0,0 +1,110 @@
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:9:1
+   |
+LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
+   | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | make this a static item (maybe with lazy_static)
+   |
+   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:10:1
+   |
+LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
+   | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | make this a static item (maybe with lazy_static)
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:11:1
+   |
+LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+   | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | make this a static item (maybe with lazy_static)
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:16:9
+   |
+LL |         const $name: $ty = $e;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
+   | ------------------------------------------ in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:40:5
+   |
+LL |     const ATOMIC: AtomicUsize; //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:44:5
+   |
+LL |     const INPUT: T;
+   |     ^^^^^^^^^^^^^-^
+   |                  |
+   |                  consider requiring `T` to be `Copy`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:47:5
+   |
+LL |     const ASSOC: Self::NonCopyType;
+   |     ^^^^^^^^^^^^^-----------------^
+   |                  |
+   |                  consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:51:5
+   |
+LL |     const AN_INPUT: T = Self::INPUT;
+   |     ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^
+   |                     |
+   |                     consider requiring `T` to be `Copy`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:16:9
+   |
+LL |         const $name: $ty = $e;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
+   |     ----------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:60:5
+   |
+LL |     const SELF_2: Self;
+   |     ^^^^^^^^^^^^^^----^
+   |                   |
+   |                   consider requiring `Self` to be `Copy`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:81:5
+   |
+LL |     const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:84:5
+   |
+LL |     const U_SELF: U = U::SELF_2;
+   |     ^^^^^^^^^^^^^^-^^^^^^^^^^^^^
+   |                   |
+   |                   consider requiring `U` to be `Copy`
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:87:5
+   |
+LL |     const T_ASSOC: T::NonCopyType = T::ASSOC;
+   |     ^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^
+   |                    |
+   |                    consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
new file mode 100644
index 00000000000..2a948d60b10
--- /dev/null
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -0,0 +1,29 @@
+// ignore-windows
+// ignore-macos
+
+#![feature(no_core, lang_items, start)]
+#![no_core]
+
+#[link(name = "c")]
+extern "C" {}
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub unsafe trait Freeze {}
+
+#[lang = "start"]
+#[start]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+pub struct A;
+
+impl A {
+    pub fn as_ref(self) -> &'static str {
+        "A"
+    }
+}
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr
new file mode 100644
index 00000000000..ed87a50547d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr
@@ -0,0 +1,10 @@
+error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
+  --> $DIR/def_id_nocore.rs:26:19
+   |
+LL |     pub fn as_ref(self) -> &'static str {
+   |                   ^^^^
+   |
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/default_lint.rs b/src/tools/clippy/tests/ui/default_lint.rs
new file mode 100644
index 00000000000..053faae02ce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_lint.rs
@@ -0,0 +1,27 @@
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+extern crate rustc_lint;
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT_DEFAULT,
+    Warn,
+    "default lint description",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+declare_lint_pass!(Pass2 => [TEST_LINT_DEFAULT]);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_lint.stderr b/src/tools/clippy/tests/ui/default_lint.stderr
new file mode 100644
index 00000000000..5c5836a7d29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_lint.stderr
@@ -0,0 +1,21 @@
+error: the lint `TEST_LINT_DEFAULT` has the default lint description
+  --> $DIR/default_lint.rs:17:1
+   |
+LL | / declare_tool_lint! {
+LL | |     pub clippy::TEST_LINT_DEFAULT,
+LL | |     Warn,
+LL | |     "default lint description",
+LL | |     report_in_external_macro: true
+LL | | }
+   | |_^
+   |
+note: the lint level is defined here
+  --> $DIR/default_lint.rs:1:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs
new file mode 100644
index 00000000000..2f1490a7036
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_trait_access.rs
@@ -0,0 +1,103 @@
+#![warn(clippy::default_trait_access)]
+
+use std::default;
+use std::default::Default as D2;
+use std::string;
+
+fn main() {
+    let s1: String = Default::default();
+
+    let s2 = String::default();
+
+    let s3: String = D2::default();
+
+    let s4: String = std::default::Default::default();
+
+    let s5 = string::String::default();
+
+    let s6: String = default::Default::default();
+
+    let s7 = std::string::String::default();
+
+    let s8: String = DefaultFactory::make_t_badly();
+
+    let s9: String = DefaultFactory::make_t_nicely();
+
+    let s10 = DerivedDefault::default();
+
+    let s11: GenericDerivedDefault<String> = Default::default();
+
+    let s12 = GenericDerivedDefault::<String>::default();
+
+    let s13 = TupleDerivedDefault::default();
+
+    let s14: TupleDerivedDefault = Default::default();
+
+    let s15: ArrayDerivedDefault = Default::default();
+
+    let s16 = ArrayDerivedDefault::default();
+
+    let s17: TupleStructDerivedDefault = Default::default();
+
+    let s18 = TupleStructDerivedDefault::default();
+
+    let s19 = <DerivedDefault as Default>::default();
+
+    println!(
+        "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]",
+        s1,
+        s2,
+        s3,
+        s4,
+        s5,
+        s6,
+        s7,
+        s8,
+        s9,
+        s10,
+        s11,
+        s12,
+        s13,
+        s14,
+        s15,
+        s16,
+        s17,
+        s18,
+        s19,
+    );
+}
+
+struct DefaultFactory;
+
+impl DefaultFactory {
+    pub fn make_t_badly<T: Default>() -> T {
+        Default::default()
+    }
+
+    pub fn make_t_nicely<T: Default>() -> T {
+        T::default()
+    }
+}
+
+#[derive(Debug, Default)]
+struct DerivedDefault {
+    pub s: String,
+}
+
+#[derive(Debug, Default)]
+struct GenericDerivedDefault<T: Default + std::fmt::Debug> {
+    pub s: T,
+}
+
+#[derive(Debug, Default)]
+struct TupleDerivedDefault {
+    pub s: (String, String),
+}
+
+#[derive(Debug, Default)]
+struct ArrayDerivedDefault {
+    pub s: [String; 10],
+}
+
+#[derive(Debug, Default)]
+struct TupleStructDerivedDefault(String);
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
new file mode 100644
index 00000000000..453760c6b92
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -0,0 +1,52 @@
+error: Calling `std::string::String::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:8:22
+   |
+LL |     let s1: String = Default::default();
+   |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |
+   = note: `-D clippy::default-trait-access` implied by `-D warnings`
+
+error: Calling `std::string::String::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:12:22
+   |
+LL |     let s3: String = D2::default();
+   |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+
+error: Calling `std::string::String::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:14:22
+   |
+LL |     let s4: String = std::default::Default::default();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+
+error: Calling `std::string::String::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:18:22
+   |
+LL |     let s6: String = default::Default::default();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+
+error: Calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:28:46
+   |
+LL |     let s11: GenericDerivedDefault<String> = Default::default();
+   |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()`
+
+error: Calling `TupleDerivedDefault::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:34:36
+   |
+LL |     let s14: TupleDerivedDefault = Default::default();
+   |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
+
+error: Calling `ArrayDerivedDefault::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:36:36
+   |
+LL |     let s15: ArrayDerivedDefault = Default::default();
+   |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
+
+error: Calling `TupleStructDerivedDefault::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:40:42
+   |
+LL |     let s17: TupleStructDerivedDefault = Default::default();
+   |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
new file mode 100644
index 00000000000..188a641aa1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -0,0 +1,11 @@
+#[warn(clippy::str_to_string)]
+#[warn(clippy::string_to_string)]
+#[warn(clippy::unstable_as_slice)]
+#[warn(clippy::unstable_as_mut_slice)]
+#[warn(clippy::misaligned_transmute)]
+#[warn(clippy::unused_collect)]
+#[warn(clippy::invalid_ref)]
+#[warn(clippy::into_iter_on_array)]
+#[warn(clippy::unused_label)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
new file mode 100644
index 00000000000..a4efe3d15a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -0,0 +1,64 @@
+error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated.rs:1:8
+   |
+LL | #[warn(clippy::str_to_string)]
+   |        ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated.rs:2:8
+   |
+LL | #[warn(clippy::string_to_string)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
+  --> $DIR/deprecated.rs:3:8
+   |
+LL | #[warn(clippy::unstable_as_slice)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
+  --> $DIR/deprecated.rs:4:8
+   |
+LL | #[warn(clippy::unstable_as_mut_slice)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
+  --> $DIR/deprecated.rs:5:8
+   |
+LL | #[warn(clippy::misaligned_transmute)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint`
+  --> $DIR/deprecated.rs:6:8
+   |
+LL | #[warn(clippy::unused_collect)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value``
+  --> $DIR/deprecated.rs:7:8
+   |
+LL | #[warn(clippy::invalid_ref)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter``
+  --> $DIR/deprecated.rs:8:8
+   |
+LL | #[warn(clippy::into_iter_on_array)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels``
+  --> $DIR/deprecated.rs:9:8
+   |
+LL | #[warn(clippy::unused_label)]
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated.rs:1:8
+   |
+LL | #[warn(clippy::str_to_string)]
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/deprecated_old.rs b/src/tools/clippy/tests/ui/deprecated_old.rs
new file mode 100644
index 00000000000..2e5c5b7ead1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deprecated_old.rs
@@ -0,0 +1,7 @@
+#[warn(str_to_string)]
+#[warn(string_to_string)]
+#[warn(unstable_as_slice)]
+#[warn(unstable_as_mut_slice)]
+#[warn(misaligned_transmute)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr
new file mode 100644
index 00000000000..ff3e9e8fcf3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deprecated_old.stderr
@@ -0,0 +1,40 @@
+error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated_old.rs:1:8
+   |
+LL | #[warn(str_to_string)]
+   |        ^^^^^^^^^^^^^
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated_old.rs:2:8
+   |
+LL | #[warn(string_to_string)]
+   |        ^^^^^^^^^^^^^^^^
+
+error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
+  --> $DIR/deprecated_old.rs:3:8
+   |
+LL | #[warn(unstable_as_slice)]
+   |        ^^^^^^^^^^^^^^^^^
+
+error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
+  --> $DIR/deprecated_old.rs:4:8
+   |
+LL | #[warn(unstable_as_mut_slice)]
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
+  --> $DIR/deprecated_old.rs:5:8
+   |
+LL | #[warn(misaligned_transmute)]
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated_old.rs:1:8
+   |
+LL | #[warn(str_to_string)]
+   |        ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed
new file mode 100644
index 00000000000..9e5b51d6d5e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof.fixed
@@ -0,0 +1,39 @@
+// run-rustfix
+
+fn get_number() -> usize {
+    10
+}
+
+fn get_reference(n: &usize) -> &usize {
+    n
+}
+
+#[allow(clippy::many_single_char_names, clippy::double_parens)]
+#[allow(unused_variables, unused_parens)]
+#[warn(clippy::deref_addrof)]
+fn main() {
+    let a = 10;
+    let aref = &a;
+
+    let b = a;
+
+    let b = get_number();
+
+    let b = *get_reference(&a);
+
+    let bytes: Vec<usize> = vec![1, 2, 3, 4];
+    let b = bytes[1..2][0];
+
+    //This produces a suggestion of 'let b = (a);' which
+    //will trigger the 'unused_parens' lint
+    let b = (a);
+
+    let b = a;
+
+    #[rustfmt::skip]
+    let b = a;
+
+    let b = &a;
+
+    let b = *aref;
+}
diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs
new file mode 100644
index 00000000000..5641a73cbc1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof.rs
@@ -0,0 +1,39 @@
+// run-rustfix
+
+fn get_number() -> usize {
+    10
+}
+
+fn get_reference(n: &usize) -> &usize {
+    n
+}
+
+#[allow(clippy::many_single_char_names, clippy::double_parens)]
+#[allow(unused_variables, unused_parens)]
+#[warn(clippy::deref_addrof)]
+fn main() {
+    let a = 10;
+    let aref = &a;
+
+    let b = *&a;
+
+    let b = *&get_number();
+
+    let b = *get_reference(&a);
+
+    let bytes: Vec<usize> = vec![1, 2, 3, 4];
+    let b = *&bytes[1..2][0];
+
+    //This produces a suggestion of 'let b = (a);' which
+    //will trigger the 'unused_parens' lint
+    let b = *&(a);
+
+    let b = *(&a);
+
+    #[rustfmt::skip]
+    let b = *((&a));
+
+    let b = *&&a;
+
+    let b = **&aref;
+}
diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr
new file mode 100644
index 00000000000..bc51719e8a7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof.stderr
@@ -0,0 +1,52 @@
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:18:13
+   |
+LL |     let b = *&a;
+   |             ^^^ help: try this: `a`
+   |
+   = note: `-D clippy::deref-addrof` implied by `-D warnings`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:20:13
+   |
+LL |     let b = *&get_number();
+   |             ^^^^^^^^^^^^^^ help: try this: `get_number()`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:25:13
+   |
+LL |     let b = *&bytes[1..2][0];
+   |             ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:29:13
+   |
+LL |     let b = *&(a);
+   |             ^^^^^ help: try this: `(a)`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:31:13
+   |
+LL |     let b = *(&a);
+   |             ^^^^^ help: try this: `a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:34:13
+   |
+LL |     let b = *((&a));
+   |             ^^^^^^^ help: try this: `a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:36:13
+   |
+LL |     let b = *&&a;
+   |             ^^^^ help: try this: `&a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:38:14
+   |
+LL |     let b = **&aref;
+   |              ^^^^^^ help: try this: `aref`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs
new file mode 100644
index 00000000000..4531943299c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs
@@ -0,0 +1,23 @@
+// This test can't work with run-rustfix because it needs two passes of test+fix
+
+#[warn(clippy::deref_addrof)]
+#[allow(unused_variables, unused_mut)]
+fn main() {
+    let a = 10;
+
+    //This produces a suggestion of 'let b = *&a;' which
+    //will trigger the 'clippy::deref_addrof' lint again
+    let b = **&&a;
+
+    {
+        let mut x = 10;
+        let y = *&mut x;
+    }
+
+    {
+        //This produces a suggestion of 'let y = *&mut x' which
+        //will trigger the 'clippy::deref_addrof' lint again
+        let mut x = 10;
+        let y = **&mut &mut x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr
new file mode 100644
index 00000000000..2c55a4ed6ac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr
@@ -0,0 +1,22 @@
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:10:14
+   |
+LL |     let b = **&&a;
+   |              ^^^^ help: try this: `&a`
+   |
+   = note: `-D clippy::deref-addrof` implied by `-D warnings`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:14:17
+   |
+LL |         let y = *&mut x;
+   |                 ^^^^^^^ help: try this: `x`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:21:18
+   |
+LL |         let y = **&mut &mut x;
+   |                  ^^^^^^^^^^^^ help: try this: `&mut x`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/deref_addrof_macro.rs b/src/tools/clippy/tests/ui/deref_addrof_macro.rs
new file mode 100644
index 00000000000..dcebd6c6e29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/deref_addrof_macro.rs
@@ -0,0 +1,10 @@
+macro_rules! m {
+    ($($x:tt),*) => { &[$(($x, stringify!(x)),)*] };
+}
+
+#[warn(clippy::deref_addrof)]
+fn f() -> [(i32, &'static str); 3] {
+    *m![1, 2, 3] // should be fine
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/dereference.fixed b/src/tools/clippy/tests/ui/dereference.fixed
new file mode 100644
index 00000000000..459ca91b93b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dereference.fixed
@@ -0,0 +1,93 @@
+// run-rustfix
+
+#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)]
+#![warn(clippy::explicit_deref_methods)]
+
+use std::ops::{Deref, DerefMut};
+
+fn concat(deref_str: &str) -> String {
+    format!("{}bar", deref_str)
+}
+
+fn just_return(deref_str: &str) -> &str {
+    deref_str
+}
+
+struct CustomVec(Vec<u8>);
+impl Deref for CustomVec {
+    type Target = Vec<u8>;
+
+    fn deref(&self) -> &Vec<u8> {
+        &self.0
+    }
+}
+
+fn main() {
+    let a: &mut String = &mut String::from("foo");
+
+    // these should require linting
+
+    let b: &str = &*a;
+
+    let b: &mut str = &mut *a;
+
+    // both derefs should get linted here
+    let b: String = format!("{}, {}", &*a, &*a);
+
+    println!("{}", &*a);
+
+    #[allow(clippy::match_single_binding)]
+    match &*a {
+        _ => (),
+    }
+
+    let b: String = concat(&*a);
+
+    let b = &*just_return(a);
+
+    let b: String = concat(&*just_return(a));
+
+    let b: &str = &*a.deref();
+
+    let opt_a = Some(a.clone());
+    let b = &*opt_a.unwrap();
+
+    // following should not require linting
+
+    let cv = CustomVec(vec![0, 42]);
+    let c = cv.deref()[0];
+
+    let b: &str = &*a.deref();
+
+    let b: String = a.deref().clone();
+
+    let b: usize = a.deref_mut().len();
+
+    let b: &usize = &a.deref().len();
+
+    let b: &str = &*a;
+
+    let b: &mut str = &mut *a;
+
+    macro_rules! expr_deref {
+        ($body:expr) => {
+            $body.deref()
+        };
+    }
+    let b: &str = expr_deref!(a);
+
+    // The struct does not implement Deref trait
+    #[derive(Copy, Clone)]
+    struct NoLint(u32);
+    impl NoLint {
+        pub fn deref(self) -> u32 {
+            self.0
+        }
+        pub fn deref_mut(self) -> u32 {
+            self.0
+        }
+    }
+    let no_lint = NoLint(42);
+    let b = no_lint.deref();
+    let b = no_lint.deref_mut();
+}
diff --git a/src/tools/clippy/tests/ui/dereference.rs b/src/tools/clippy/tests/ui/dereference.rs
new file mode 100644
index 00000000000..8dc5272e67f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dereference.rs
@@ -0,0 +1,93 @@
+// run-rustfix
+
+#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)]
+#![warn(clippy::explicit_deref_methods)]
+
+use std::ops::{Deref, DerefMut};
+
+fn concat(deref_str: &str) -> String {
+    format!("{}bar", deref_str)
+}
+
+fn just_return(deref_str: &str) -> &str {
+    deref_str
+}
+
+struct CustomVec(Vec<u8>);
+impl Deref for CustomVec {
+    type Target = Vec<u8>;
+
+    fn deref(&self) -> &Vec<u8> {
+        &self.0
+    }
+}
+
+fn main() {
+    let a: &mut String = &mut String::from("foo");
+
+    // these should require linting
+
+    let b: &str = a.deref();
+
+    let b: &mut str = a.deref_mut();
+
+    // both derefs should get linted here
+    let b: String = format!("{}, {}", a.deref(), a.deref());
+
+    println!("{}", a.deref());
+
+    #[allow(clippy::match_single_binding)]
+    match a.deref() {
+        _ => (),
+    }
+
+    let b: String = concat(a.deref());
+
+    let b = just_return(a).deref();
+
+    let b: String = concat(just_return(a).deref());
+
+    let b: &str = a.deref().deref();
+
+    let opt_a = Some(a.clone());
+    let b = opt_a.unwrap().deref();
+
+    // following should not require linting
+
+    let cv = CustomVec(vec![0, 42]);
+    let c = cv.deref()[0];
+
+    let b: &str = &*a.deref();
+
+    let b: String = a.deref().clone();
+
+    let b: usize = a.deref_mut().len();
+
+    let b: &usize = &a.deref().len();
+
+    let b: &str = &*a;
+
+    let b: &mut str = &mut *a;
+
+    macro_rules! expr_deref {
+        ($body:expr) => {
+            $body.deref()
+        };
+    }
+    let b: &str = expr_deref!(a);
+
+    // The struct does not implement Deref trait
+    #[derive(Copy, Clone)]
+    struct NoLint(u32);
+    impl NoLint {
+        pub fn deref(self) -> u32 {
+            self.0
+        }
+        pub fn deref_mut(self) -> u32 {
+            self.0
+        }
+    }
+    let no_lint = NoLint(42);
+    let b = no_lint.deref();
+    let b = no_lint.deref_mut();
+}
diff --git a/src/tools/clippy/tests/ui/dereference.stderr b/src/tools/clippy/tests/ui/dereference.stderr
new file mode 100644
index 00000000000..d26b462a433
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dereference.stderr
@@ -0,0 +1,70 @@
+error: explicit deref method call
+  --> $DIR/dereference.rs:30:19
+   |
+LL |     let b: &str = a.deref();
+   |                   ^^^^^^^^^ help: try this: `&*a`
+   |
+   = note: `-D clippy::explicit-deref-methods` implied by `-D warnings`
+
+error: explicit deref_mut method call
+  --> $DIR/dereference.rs:32:23
+   |
+LL |     let b: &mut str = a.deref_mut();
+   |                       ^^^^^^^^^^^^^ help: try this: `&mut *a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:35:39
+   |
+LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
+   |                                       ^^^^^^^^^ help: try this: `&*a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:35:50
+   |
+LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
+   |                                                  ^^^^^^^^^ help: try this: `&*a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:37:20
+   |
+LL |     println!("{}", a.deref());
+   |                    ^^^^^^^^^ help: try this: `&*a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:40:11
+   |
+LL |     match a.deref() {
+   |           ^^^^^^^^^ help: try this: `&*a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:44:28
+   |
+LL |     let b: String = concat(a.deref());
+   |                            ^^^^^^^^^ help: try this: `&*a`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:46:13
+   |
+LL |     let b = just_return(a).deref();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:48:28
+   |
+LL |     let b: String = concat(just_return(a).deref());
+   |                            ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:50:19
+   |
+LL |     let b: &str = a.deref().deref();
+   |                   ^^^^^^^^^^^^^^^^^ help: try this: `&*a.deref()`
+
+error: explicit deref method call
+  --> $DIR/dereference.rs:53:13
+   |
+LL |     let b = opt_a.unwrap().deref();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
new file mode 100644
index 00000000000..8fcb0e8b28d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -0,0 +1,74 @@
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![warn(clippy::expl_impl_clone_on_copy)]
+
+#[derive(Copy)]
+struct Qux;
+
+impl Clone for Qux {
+    fn clone(&self) -> Self {
+        Qux
+    }
+}
+
+// looks like unions don't support deriving Clone for now
+#[derive(Copy)]
+union Union {
+    a: u8,
+}
+
+impl Clone for Union {
+    fn clone(&self) -> Self {
+        Union { a: 42 }
+    }
+}
+
+// See #666
+#[derive(Copy)]
+struct Lt<'a> {
+    a: &'a u8,
+}
+
+impl<'a> Clone for Lt<'a> {
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
+}
+
+// Ok, `Clone` cannot be derived because of the big array
+#[derive(Copy)]
+struct BigArray {
+    a: [u8; 65],
+}
+
+impl Clone for BigArray {
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
+}
+
+// Ok, function pointers are not always Clone
+#[derive(Copy)]
+struct FnPtr {
+    a: fn() -> !,
+}
+
+impl Clone for FnPtr {
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
+}
+
+// Ok, generics
+#[derive(Copy)]
+struct Generic<T> {
+    a: T,
+}
+
+impl<T> Clone for Generic<T> {
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
new file mode 100644
index 00000000000..1328a9b3107
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -0,0 +1,83 @@
+error: you are implementing `Clone` explicitly on a `Copy` type
+  --> $DIR/derive.rs:8:1
+   |
+LL | / impl Clone for Qux {
+LL | |     fn clone(&self) -> Self {
+LL | |         Qux
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
+note: consider deriving `Clone` or removing `Copy`
+  --> $DIR/derive.rs:8:1
+   |
+LL | / impl Clone for Qux {
+LL | |     fn clone(&self) -> Self {
+LL | |         Qux
+LL | |     }
+LL | | }
+   | |_^
+
+error: you are implementing `Clone` explicitly on a `Copy` type
+  --> $DIR/derive.rs:32:1
+   |
+LL | / impl<'a> Clone for Lt<'a> {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: consider deriving `Clone` or removing `Copy`
+  --> $DIR/derive.rs:32:1
+   |
+LL | / impl<'a> Clone for Lt<'a> {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+
+error: you are implementing `Clone` explicitly on a `Copy` type
+  --> $DIR/derive.rs:44:1
+   |
+LL | / impl Clone for BigArray {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: consider deriving `Clone` or removing `Copy`
+  --> $DIR/derive.rs:44:1
+   |
+LL | / impl Clone for BigArray {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+
+error: you are implementing `Clone` explicitly on a `Copy` type
+  --> $DIR/derive.rs:56:1
+   |
+LL | / impl Clone for FnPtr {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: consider deriving `Clone` or removing `Copy`
+  --> $DIR/derive.rs:56:1
+   |
+LL | / impl Clone for FnPtr {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
+   | |_^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs b/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
new file mode 100644
index 00000000000..10abe22d53e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs
@@ -0,0 +1,54 @@
+#[derive(PartialEq, Hash)]
+struct Foo;
+
+impl PartialEq<u64> for Foo {
+    fn eq(&self, _: &u64) -> bool {
+        true
+    }
+}
+
+#[derive(Hash)]
+struct Bar;
+
+impl PartialEq for Bar {
+    fn eq(&self, _: &Bar) -> bool {
+        true
+    }
+}
+
+#[derive(Hash)]
+struct Baz;
+
+impl PartialEq<Baz> for Baz {
+    fn eq(&self, _: &Baz) -> bool {
+        true
+    }
+}
+
+#[derive(PartialEq)]
+struct Bah;
+
+impl std::hash::Hash for Bah {
+    fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
+}
+
+#[derive(PartialEq)]
+struct Foo2;
+
+trait Hash {}
+
+// We don't want to lint on user-defined traits called `Hash`
+impl Hash for Foo2 {}
+
+mod use_hash {
+    use std::hash::{Hash, Hasher};
+
+    #[derive(PartialEq)]
+    struct Foo3;
+
+    impl Hash for Foo3 {
+        fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
new file mode 100644
index 00000000000..2287a548fe4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
@@ -0,0 +1,67 @@
+error: you are deriving `Hash` but have implemented `PartialEq` explicitly
+  --> $DIR/derive_hash_xor_eq.rs:10:10
+   |
+LL | #[derive(Hash)]
+   |          ^^^^
+   |
+   = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
+note: `PartialEq` implemented here
+  --> $DIR/derive_hash_xor_eq.rs:13:1
+   |
+LL | / impl PartialEq for Bar {
+LL | |     fn eq(&self, _: &Bar) -> bool {
+LL | |         true
+LL | |     }
+LL | | }
+   | |_^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `Hash` but have implemented `PartialEq` explicitly
+  --> $DIR/derive_hash_xor_eq.rs:19:10
+   |
+LL | #[derive(Hash)]
+   |          ^^^^
+   |
+note: `PartialEq` implemented here
+  --> $DIR/derive_hash_xor_eq.rs:22:1
+   |
+LL | / impl PartialEq<Baz> for Baz {
+LL | |     fn eq(&self, _: &Baz) -> bool {
+LL | |         true
+LL | |     }
+LL | | }
+   | |_^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are implementing `Hash` explicitly but have derived `PartialEq`
+  --> $DIR/derive_hash_xor_eq.rs:31:1
+   |
+LL | / impl std::hash::Hash for Bah {
+LL | |     fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
+LL | | }
+   | |_^
+   |
+note: `PartialEq` implemented here
+  --> $DIR/derive_hash_xor_eq.rs:28:10
+   |
+LL | #[derive(PartialEq)]
+   |          ^^^^^^^^^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are implementing `Hash` explicitly but have derived `PartialEq`
+  --> $DIR/derive_hash_xor_eq.rs:49:5
+   |
+LL | /     impl Hash for Foo3 {
+LL | |         fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
+LL | |     }
+   | |_____^
+   |
+note: `PartialEq` implemented here
+  --> $DIR/derive_hash_xor_eq.rs:46:14
+   |
+LL |     #[derive(PartialEq)]
+   |              ^^^^^^^^^
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
new file mode 100644
index 00000000000..4df241c9fc3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::diverging_sub_expression)]
+#![allow(clippy::match_same_arms, clippy::logic_bug)]
+
+#[allow(clippy::empty_loop)]
+fn diverge() -> ! {
+    loop {}
+}
+
+struct A;
+
+impl A {
+    fn foo(&self) -> ! {
+        diverge()
+    }
+}
+
+#[allow(unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
+fn main() {
+    let b = true;
+    b || diverge();
+    b || A.foo();
+}
+
+#[allow(dead_code, unused_variables)]
+fn foobar() {
+    loop {
+        let x = match 5 {
+            4 => return,
+            5 => continue,
+            6 => true || return,
+            7 => true || continue,
+            8 => break,
+            9 => diverge(),
+            3 => true || diverge(),
+            10 => match 42 {
+                99 => return,
+                _ => true || panic!("boo"),
+            },
+            _ => true || break,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr
new file mode 100644
index 00000000000..170e7d92de4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr
@@ -0,0 +1,40 @@
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:20:10
+   |
+LL |     b || diverge();
+   |          ^^^^^^^^^
+   |
+   = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:21:10
+   |
+LL |     b || A.foo();
+   |          ^^^^^^^
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:30:26
+   |
+LL |             6 => true || return,
+   |                          ^^^^^^
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:31:26
+   |
+LL |             7 => true || continue,
+   |                          ^^^^^^^^
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:34:26
+   |
+LL |             3 => true || diverge(),
+   |                          ^^^^^^^^^
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:39:26
+   |
+LL |             _ => true || break,
+   |                          ^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/dlist.rs b/src/tools/clippy/tests/ui/dlist.rs
new file mode 100644
index 00000000000..2940d2d2901
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dlist.rs
@@ -0,0 +1,40 @@
+#![feature(associated_type_defaults)]
+#![warn(clippy::linkedlist)]
+#![allow(dead_code, clippy::needless_pass_by_value)]
+
+extern crate alloc;
+use alloc::collections::linked_list::LinkedList;
+
+trait Foo {
+    type Baz = LinkedList<u8>;
+    fn foo(_: LinkedList<u8>);
+    const BAR: Option<LinkedList<u8>>;
+}
+
+// Ok, we don’t want to warn for implementations; see issue #605.
+impl Foo for LinkedList<u8> {
+    fn foo(_: LinkedList<u8>) {}
+    const BAR: Option<LinkedList<u8>> = None;
+}
+
+struct Bar;
+impl Bar {
+    fn foo(_: LinkedList<u8>) {}
+}
+
+pub fn test(my_favourite_linked_list: LinkedList<u8>) {
+    println!("{:?}", my_favourite_linked_list)
+}
+
+pub fn test_ret() -> Option<LinkedList<u8>> {
+    unimplemented!();
+}
+
+pub fn test_local_not_linted() {
+    let _: LinkedList<u8>;
+}
+
+fn main() {
+    test(LinkedList::new());
+    test_local_not_linted();
+}
diff --git a/src/tools/clippy/tests/ui/dlist.stderr b/src/tools/clippy/tests/ui/dlist.stderr
new file mode 100644
index 00000000000..64fde33c64f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dlist.stderr
@@ -0,0 +1,51 @@
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:9:16
+   |
+LL |     type Baz = LinkedList<u8>;
+   |                ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::linkedlist` implied by `-D warnings`
+   = help: a `VecDeque` might work
+
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:10:15
+   |
+LL |     fn foo(_: LinkedList<u8>);
+   |               ^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:11:23
+   |
+LL |     const BAR: Option<LinkedList<u8>>;
+   |                       ^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:22:15
+   |
+LL |     fn foo(_: LinkedList<u8>) {}
+   |               ^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:25:39
+   |
+LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
+   |                                       ^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: I see you're using a LinkedList! Perhaps you meant some other data structure?
+  --> $DIR/dlist.rs:29:29
+   |
+LL | pub fn test_ret() -> Option<LinkedList<u8>> {
+   |                             ^^^^^^^^^^^^^^
+   |
+   = help: a `VecDeque` might work
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc.rs b/src/tools/clippy/tests/ui/doc.rs
new file mode 100644
index 00000000000..77620c857e6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc.rs
@@ -0,0 +1,184 @@
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
+/// which should be reported only once despite being __doubly bad__.
+/// Here be ::a::global:path.
+/// That's not code ~NotInCodeBlock~.
+/// be_sure_we_got_to_the_end_of_it
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// be_sure_we_got_to_the_end_of_it
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// be_sure_we_got_to_the_end_of_it
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// be_sure_we_got_to_the_end_of_it
+fn test_units() {
+}
+
+/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [inline_link2].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// be_sure_we_got_to_the_end_of_it
+fn main() {
+    foo_bar();
+    multiline_codeblock();
+    test_emphasis();
+    test_units();
+}
+
+/// ## CamelCaseThing
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # CamelCaseThing
+///
+/// Not a title #897 CamelCaseThing
+/// be_sure_we_got_to_the_end_of_it
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// be_sure_we_got_to_the_end_of_it
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// be_sure_we_got_to_the_end_of_it
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: `PackedNode`
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: PackedNode
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// be_sure_we_got_to_the_end_of_it
+fn four_quotes() {
+}
+
+/// See [NIST SP 800-56A, revision 2].
+///
+/// [NIST SP 800-56A, revision 2]:
+///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
+fn issue_902_comment() {}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+///     let s = "localhost:10000".to_string();
+///     println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
+///
+/// Not ok: http://www.unicode.org
+/// Not ok: https://www.unicode.org
+/// Not ok: http://www.unicode.org/
+/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+fn issue_1832() {}
+
+/// Ok: CamelCase (It should not be surrounded by backticks)
+fn issue_2395() {}
+
+/// An iterator over mycrate::Collection's values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
diff --git a/src/tools/clippy/tests/ui/doc.stderr b/src/tools/clippy/tests/ui/doc.stderr
new file mode 100644
index 00000000000..ae9bb394cb9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc.stderr
@@ -0,0 +1,184 @@
+error: you should put `foo_bar` between ticks in the documentation
+  --> $DIR/doc.rs:8:9
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::doc-markdown` implied by `-D warnings`
+
+error: you should put `foo::bar` between ticks in the documentation
+  --> $DIR/doc.rs:8:51
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |                                                   ^^^^^^^^
+
+error: you should put `Foo::some_fun` between ticks in the documentation
+  --> $DIR/doc.rs:9:83
+   |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
+   |                                                                                   ^^^^^^^^^^^^^
+
+error: you should put `a::global:path` between ticks in the documentation
+  --> $DIR/doc.rs:11:15
+   |
+LL | /// Here be ::a::global:path.
+   |               ^^^^^^^^^^^^^^
+
+error: you should put `NotInCodeBlock` between ticks in the documentation
+  --> $DIR/doc.rs:12:22
+   |
+LL | /// That's not code ~NotInCodeBlock~.
+   |                      ^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:13:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:27:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:34:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:48:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `link_with_underscores` between ticks in the documentation
+  --> $DIR/doc.rs:52:22
+   |
+LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+   |                      ^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `inline_link2` between ticks in the documentation
+  --> $DIR/doc.rs:55:21
+   |
+LL | /// It can also be [inline_link2].
+   |                     ^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:65:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `CamelCaseThing` between ticks in the documentation
+  --> $DIR/doc.rs:73:8
+   |
+LL | /// ## CamelCaseThing
+   |        ^^^^^^^^^^^^^^
+
+error: you should put `CamelCaseThing` between ticks in the documentation
+  --> $DIR/doc.rs:76:7
+   |
+LL | /// # CamelCaseThing
+   |       ^^^^^^^^^^^^^^
+
+error: you should put `CamelCaseThing` between ticks in the documentation
+  --> $DIR/doc.rs:78:22
+   |
+LL | /// Not a title #897 CamelCaseThing
+   |                      ^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:79:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:86:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:99:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `FooBar` between ticks in the documentation
+  --> $DIR/doc.rs:110:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+   |                                           ^^^^^^
+
+error: you should put `BarQuz` between ticks in the documentation
+  --> $DIR/doc.rs:115:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:116:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `FooBar` between ticks in the documentation
+  --> $DIR/doc.rs:121:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+   |                                           ^^^^^^
+
+error: you should put `BarQuz` between ticks in the documentation
+  --> $DIR/doc.rs:126:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:127:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:138:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put bare URLs between `<`/`>` or make a proper Markdown link
+  --> $DIR/doc.rs:165:13
+   |
+LL | /// Not ok: http://www.unicode.org
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put bare URLs between `<`/`>` or make a proper Markdown link
+  --> $DIR/doc.rs:166:13
+   |
+LL | /// Not ok: https://www.unicode.org
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put bare URLs between `<`/`>` or make a proper Markdown link
+  --> $DIR/doc.rs:167:13
+   |
+LL | /// Not ok: http://www.unicode.org/
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put bare URLs between `<`/`>` or make a proper Markdown link
+  --> $DIR/doc.rs:168:13
+   |
+LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `mycrate::Collection` between ticks in the documentation
+  --> $DIR/doc.rs:174:22
+   |
+LL | /// An iterator over mycrate::Collection's values.
+   |                      ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 30 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs
new file mode 100644
index 00000000000..445fc8d31d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_errors.rs
@@ -0,0 +1,103 @@
+// edition:2018
+#![warn(clippy::missing_errors_doc)]
+
+use std::io;
+
+pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+/// This is not sufficiently documented.
+pub fn pub_fn_returning_io_result() -> io::Result<()> {
+    unimplemented!();
+}
+
+/// This is not sufficiently documented.
+pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
+    unimplemented!();
+}
+
+/// # Errors
+/// A description of the errors goes here.
+pub fn pub_fn_with_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+/// # Errors
+/// A description of the errors goes here.
+pub async fn async_pub_fn_with_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+/// This function doesn't require the documentation because it is private
+fn priv_fn_missing_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+/// This function doesn't require the documentation because it is private
+async fn async_priv_fn_missing_errors_header() -> Result<(), ()> {
+    unimplemented!();
+}
+
+pub struct Struct1;
+
+impl Struct1 {
+    /// This is not sufficiently documented.
+    pub fn pub_method_missing_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /// This is not sufficiently documented.
+    pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /// # Errors
+    /// A description of the errors goes here.
+    pub fn pub_method_with_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /// # Errors
+    /// A description of the errors goes here.
+    pub async fn async_pub_method_with_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /// This function doesn't require the documentation because it is private.
+    fn priv_method_missing_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    /// This function doesn't require the documentation because it is private.
+    async fn async_priv_method_missing_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+}
+
+pub trait Trait1 {
+    /// This is not sufficiently documented.
+    fn trait_method_missing_errors_header() -> Result<(), ()>;
+
+    /// # Errors
+    /// A description of the errors goes here.
+    fn trait_method_with_errors_header() -> Result<(), ()>;
+}
+
+impl Trait1 for Struct1 {
+    fn trait_method_missing_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+
+    fn trait_method_with_errors_header() -> Result<(), ()> {
+        unimplemented!();
+    }
+}
+
+fn main() -> Result<(), ()> {
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr
new file mode 100644
index 00000000000..f44d6693d30
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_errors.stderr
@@ -0,0 +1,58 @@
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:6:1
+   |
+LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
+LL | |     unimplemented!();
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::missing-errors-doc` implied by `-D warnings`
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:10:1
+   |
+LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
+LL | |     unimplemented!();
+LL | | }
+   | |_^
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:15:1
+   |
+LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
+LL | |     unimplemented!();
+LL | | }
+   | |_^
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:20:1
+   |
+LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
+LL | |     unimplemented!();
+LL | | }
+   | |_^
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:50:5
+   |
+LL | /     pub fn pub_method_missing_errors_header() -> Result<(), ()> {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:55:5
+   |
+LL | /     pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: docs for function returning `Result` missing `# Errors` section
+  --> $DIR/doc_errors.rs:84:5
+   |
+LL |     fn trait_method_missing_errors_header() -> Result<(), ()>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs
new file mode 100644
index 00000000000..484aa72d59a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_unsafe.rs
@@ -0,0 +1,100 @@
+// aux-build:doc_unsafe_macros.rs
+
+#[macro_use]
+extern crate doc_unsafe_macros;
+
+/// This is not sufficiently documented
+pub unsafe fn destroy_the_planet() {
+    unimplemented!();
+}
+
+/// This one is
+///
+/// # Safety
+///
+/// This function shouldn't be called unless the horsemen are ready
+pub unsafe fn apocalypse(universe: &mut ()) {
+    unimplemented!();
+}
+
+/// This is a private function, so docs aren't necessary
+unsafe fn you_dont_see_me() {
+    unimplemented!();
+}
+
+mod private_mod {
+    pub unsafe fn only_crate_wide_accessible() {
+        unimplemented!();
+    }
+
+    pub unsafe fn republished() {
+        unimplemented!();
+    }
+}
+
+pub use private_mod::republished;
+
+pub trait UnsafeTrait {
+    unsafe fn woefully_underdocumented(self);
+
+    /// # Safety
+    unsafe fn at_least_somewhat_documented(self);
+}
+
+pub struct Struct;
+
+impl UnsafeTrait for Struct {
+    unsafe fn woefully_underdocumented(self) {
+        // all is well
+    }
+
+    unsafe fn at_least_somewhat_documented(self) {
+        // all is still well
+    }
+}
+
+impl Struct {
+    pub unsafe fn more_undocumented_unsafe() -> Self {
+        unimplemented!();
+    }
+
+    /// # Safety
+    pub unsafe fn somewhat_documented(&self) {
+        unimplemented!();
+    }
+
+    unsafe fn private(&self) {
+        unimplemented!();
+    }
+}
+
+macro_rules! very_unsafe {
+    () => {
+        pub unsafe fn whee() {
+            unimplemented!()
+        }
+
+        /// # Safety
+        ///
+        /// Please keep the seat belt fastened
+        pub unsafe fn drive() {
+            whee()
+        }
+    };
+}
+
+very_unsafe!();
+
+// we don't lint code from external macros
+undocd_unsafe!();
+
+fn main() {
+    unsafe {
+        you_dont_see_me();
+        destroy_the_planet();
+        let mut universe = ();
+        apocalypse(&mut universe);
+        private_mod::only_crate_wide_accessible();
+        drive();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/doc_unsafe.stderr b/src/tools/clippy/tests/ui/doc_unsafe.stderr
new file mode 100644
index 00000000000..c784d41ba17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_unsafe.stderr
@@ -0,0 +1,47 @@
+error: unsafe function's docs miss `# Safety` section
+  --> $DIR/doc_unsafe.rs:7:1
+   |
+LL | / pub unsafe fn destroy_the_planet() {
+LL | |     unimplemented!();
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::missing-safety-doc` implied by `-D warnings`
+
+error: unsafe function's docs miss `# Safety` section
+  --> $DIR/doc_unsafe.rs:30:5
+   |
+LL | /     pub unsafe fn republished() {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: unsafe function's docs miss `# Safety` section
+  --> $DIR/doc_unsafe.rs:38:5
+   |
+LL |     unsafe fn woefully_underdocumented(self);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unsafe function's docs miss `# Safety` section
+  --> $DIR/doc_unsafe.rs:57:5
+   |
+LL | /     pub unsafe fn more_undocumented_unsafe() -> Self {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: unsafe function's docs miss `# Safety` section
+  --> $DIR/doc_unsafe.rs:73:9
+   |
+LL | /         pub unsafe fn whee() {
+LL | |             unimplemented!()
+LL | |         }
+   | |_________^
+...
+LL |   very_unsafe!();
+   |   --------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/double_comparison.fixed b/src/tools/clippy/tests/ui/double_comparison.fixed
new file mode 100644
index 00000000000..bb6cdaa667d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_comparison.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+
+fn main() {
+    let x = 1;
+    let y = 2;
+    if x <= y {
+        // do something
+    }
+    if x <= y {
+        // do something
+    }
+    if x >= y {
+        // do something
+    }
+    if x >= y {
+        // do something
+    }
+    if x != y {
+        // do something
+    }
+    if x != y {
+        // do something
+    }
+    if x == y {
+        // do something
+    }
+    if x == y {
+        // do something
+    }
+}
diff --git a/src/tools/clippy/tests/ui/double_comparison.rs b/src/tools/clippy/tests/ui/double_comparison.rs
new file mode 100644
index 00000000000..9a2a9068a28
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_comparison.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+
+fn main() {
+    let x = 1;
+    let y = 2;
+    if x == y || x < y {
+        // do something
+    }
+    if x < y || x == y {
+        // do something
+    }
+    if x == y || x > y {
+        // do something
+    }
+    if x > y || x == y {
+        // do something
+    }
+    if x < y || x > y {
+        // do something
+    }
+    if x > y || x < y {
+        // do something
+    }
+    if x <= y && x >= y {
+        // do something
+    }
+    if x >= y && x <= y {
+        // do something
+    }
+}
diff --git a/src/tools/clippy/tests/ui/double_comparison.stderr b/src/tools/clippy/tests/ui/double_comparison.stderr
new file mode 100644
index 00000000000..5dcda7b3af4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_comparison.stderr
@@ -0,0 +1,52 @@
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:6:8
+   |
+LL |     if x == y || x < y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
+   |
+   = note: `-D clippy::double-comparisons` implied by `-D warnings`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:9:8
+   |
+LL |     if x < y || x == y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:12:8
+   |
+LL |     if x == y || x > y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:15:8
+   |
+LL |     if x > y || x == y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:18:8
+   |
+LL |     if x < y || x > y {
+   |        ^^^^^^^^^^^^^^ help: try: `x != y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:21:8
+   |
+LL |     if x > y || x < y {
+   |        ^^^^^^^^^^^^^^ help: try: `x != y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:24:8
+   |
+LL |     if x <= y && x >= y {
+   |        ^^^^^^^^^^^^^^^^ help: try: `x == y`
+
+error: This binary expression can be simplified
+  --> $DIR/double_comparison.rs:27:8
+   |
+LL |     if x >= y && x <= y {
+   |        ^^^^^^^^^^^^^^^^ help: try: `x == y`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/double_must_use.rs b/src/tools/clippy/tests/ui/double_must_use.rs
new file mode 100644
index 00000000000..a48e675e4ea
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_must_use.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::double_must_use)]
+
+#[must_use]
+pub fn must_use_result() -> Result<(), ()> {
+    unimplemented!();
+}
+
+#[must_use]
+pub fn must_use_tuple() -> (Result<(), ()>, u8) {
+    unimplemented!();
+}
+
+#[must_use]
+pub fn must_use_array() -> [Result<(), ()>; 1] {
+    unimplemented!();
+}
+
+#[must_use = "With note"]
+pub fn must_use_with_note() -> Result<(), ()> {
+    unimplemented!();
+}
+
+fn main() {
+    must_use_result();
+    must_use_tuple();
+    must_use_with_note();
+}
diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr
new file mode 100644
index 00000000000..bc37785294f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_must_use.stderr
@@ -0,0 +1,27 @@
+error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
+  --> $DIR/double_must_use.rs:4:1
+   |
+LL | pub fn must_use_result() -> Result<(), ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::double-must-use` implied by `-D warnings`
+   = help: either add some descriptive text or remove the attribute
+
+error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
+  --> $DIR/double_must_use.rs:9:1
+   |
+LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: either add some descriptive text or remove the attribute
+
+error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
+  --> $DIR/double_must_use.rs:14:1
+   |
+LL | pub fn must_use_array() -> [Result<(), ()>; 1] {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: either add some descriptive text or remove the attribute
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/double_neg.rs b/src/tools/clippy/tests/ui/double_neg.rs
new file mode 100644
index 00000000000..d47dfcb5ba1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_neg.rs
@@ -0,0 +1,7 @@
+#[warn(clippy::double_neg)]
+fn main() {
+    let x = 1;
+    -x;
+    -(-x);
+    --x;
+}
diff --git a/src/tools/clippy/tests/ui/double_neg.stderr b/src/tools/clippy/tests/ui/double_neg.stderr
new file mode 100644
index 00000000000..d82ed05f054
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_neg.stderr
@@ -0,0 +1,10 @@
+error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
+  --> $DIR/double_neg.rs:6:5
+   |
+LL |     --x;
+   |     ^^^
+   |
+   = note: `-D clippy::double-neg` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/double_parens.rs b/src/tools/clippy/tests/ui/double_parens.rs
new file mode 100644
index 00000000000..9c7590c7dd6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_parens.rs
@@ -0,0 +1,56 @@
+#![warn(clippy::double_parens)]
+#![allow(dead_code)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+fn dummy_fn<T>(_: T) {}
+
+struct DummyStruct;
+
+impl DummyStruct {
+    fn dummy_method<T>(self, _: T) {}
+}
+
+fn simple_double_parens() -> i32 {
+    ((0))
+}
+
+fn fn_double_parens() {
+    dummy_fn((0));
+}
+
+fn method_double_parens(x: DummyStruct) {
+    x.dummy_method((0));
+}
+
+fn tuple_double_parens() -> (i32, i32) {
+    ((1, 2))
+}
+
+fn unit_double_parens() {
+    (())
+}
+
+fn fn_tuple_ok() {
+    dummy_fn((1, 2));
+}
+
+fn method_tuple_ok(x: DummyStruct) {
+    x.dummy_method((1, 2));
+}
+
+fn fn_unit_ok() {
+    dummy_fn(());
+}
+
+fn method_unit_ok(x: DummyStruct) {
+    x.dummy_method(());
+}
+
+// Issue #3206
+fn inside_macro() {
+    assert_eq!((1, 2), (1, 2), "Error");
+    assert_eq!(((1, 2)), (1, 2), "Error");
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/double_parens.stderr b/src/tools/clippy/tests/ui/double_parens.stderr
new file mode 100644
index 00000000000..0e4c9b5682d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_parens.stderr
@@ -0,0 +1,40 @@
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:15:5
+   |
+LL |     ((0))
+   |     ^^^^^
+   |
+   = note: `-D clippy::double-parens` implied by `-D warnings`
+
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:19:14
+   |
+LL |     dummy_fn((0));
+   |              ^^^
+
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:23:20
+   |
+LL |     x.dummy_method((0));
+   |                    ^^^
+
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:27:5
+   |
+LL |     ((1, 2))
+   |     ^^^^^^^^
+
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:31:5
+   |
+LL |     (())
+   |     ^^^^
+
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:53:16
+   |
+LL |     assert_eq!(((1, 2)), (1, 2), "Error");
+   |                ^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/drop_bounds.rs b/src/tools/clippy/tests/ui/drop_bounds.rs
new file mode 100644
index 00000000000..6d6a9dc0783
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_bounds.rs
@@ -0,0 +1,8 @@
+#![allow(unused)]
+fn foo<T: Drop>() {}
+fn bar<T>()
+where
+    T: Drop,
+{
+}
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/drop_bounds.stderr b/src/tools/clippy/tests/ui/drop_bounds.stderr
new file mode 100644
index 00000000000..5d360ef30a1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_bounds.stderr
@@ -0,0 +1,16 @@
+error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+  --> $DIR/drop_bounds.rs:2:11
+   |
+LL | fn foo<T: Drop>() {}
+   |           ^^^^
+   |
+   = note: `#[deny(clippy::drop_bounds)]` on by default
+
+error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+  --> $DIR/drop_bounds.rs:5:8
+   |
+LL |     T: Drop,
+   |        ^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.rs b/src/tools/clippy/tests/ui/drop_forget_copy.rs
new file mode 100644
index 00000000000..9ddd6d64701
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_forget_copy.rs
@@ -0,0 +1,66 @@
+#![warn(clippy::drop_copy, clippy::forget_copy)]
+#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)]
+
+use std::mem::{drop, forget};
+use std::vec::Vec;
+
+#[derive(Copy, Clone)]
+struct SomeStruct {}
+
+struct AnotherStruct {
+    x: u8,
+    y: u8,
+    z: Vec<u8>,
+}
+
+impl Clone for AnotherStruct {
+    fn clone(&self) -> AnotherStruct {
+        AnotherStruct {
+            x: self.x,
+            y: self.y,
+            z: self.z.clone(),
+        }
+    }
+}
+
+fn main() {
+    let s1 = SomeStruct {};
+    let s2 = s1;
+    let s3 = &s1;
+    let mut s4 = s1;
+    let ref s5 = s1;
+
+    drop(s1);
+    drop(s2);
+    drop(s3);
+    drop(s4);
+    drop(s5);
+
+    forget(s1);
+    forget(s2);
+    forget(s3);
+    forget(s4);
+    forget(s5);
+
+    let a1 = AnotherStruct {
+        x: 255,
+        y: 0,
+        z: vec![1, 2, 3],
+    };
+    let a2 = &a1;
+    let mut a3 = a1.clone();
+    let ref a4 = a1;
+    let a5 = a1.clone();
+
+    drop(a2);
+    drop(a3);
+    drop(a4);
+    drop(a5);
+
+    forget(a2);
+    let a3 = &a1;
+    forget(a3);
+    forget(a4);
+    let a5 = a1.clone();
+    forget(a5);
+}
diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.stderr b/src/tools/clippy/tests/ui/drop_forget_copy.stderr
new file mode 100644
index 00000000000..82a4f047ba8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_forget_copy.stderr
@@ -0,0 +1,76 @@
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:33:5
+   |
+LL |     drop(s1);
+   |     ^^^^^^^^
+   |
+   = note: `-D clippy::drop-copy` implied by `-D warnings`
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:33:10
+   |
+LL |     drop(s1);
+   |          ^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:34:5
+   |
+LL |     drop(s2);
+   |     ^^^^^^^^
+   |
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:34:10
+   |
+LL |     drop(s2);
+   |          ^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:36:5
+   |
+LL |     drop(s4);
+   |     ^^^^^^^^
+   |
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:36:10
+   |
+LL |     drop(s4);
+   |          ^^
+
+error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:39:5
+   |
+LL |     forget(s1);
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::forget-copy` implied by `-D warnings`
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:39:12
+   |
+LL |     forget(s1);
+   |            ^^
+
+error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:40:5
+   |
+LL |     forget(s2);
+   |     ^^^^^^^^^^
+   |
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:40:12
+   |
+LL |     forget(s2);
+   |            ^^
+
+error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact.
+  --> $DIR/drop_forget_copy.rs:42:5
+   |
+LL |     forget(s4);
+   |     ^^^^^^^^^^
+   |
+note: argument has type SomeStruct
+  --> $DIR/drop_forget_copy.rs:42:12
+   |
+LL |     forget(s4);
+   |            ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/src/tools/clippy/tests/ui/drop_ref.rs
new file mode 100644
index 00000000000..9181d789d4f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_ref.rs
@@ -0,0 +1,72 @@
+#![warn(clippy::drop_ref)]
+#![allow(clippy::toplevel_ref_arg)]
+
+use std::mem::drop;
+
+struct SomeStruct;
+
+fn main() {
+    drop(&SomeStruct);
+
+    let mut owned1 = SomeStruct;
+    drop(&owned1);
+    drop(&&owned1);
+    drop(&mut owned1);
+    drop(owned1); //OK
+
+    let reference1 = &SomeStruct;
+    drop(reference1);
+
+    let reference2 = &mut SomeStruct;
+    drop(reference2);
+
+    let ref reference3 = SomeStruct;
+    drop(reference3);
+}
+
+#[allow(dead_code)]
+fn test_generic_fn_drop<T>(val: T) {
+    drop(&val);
+    drop(val); //OK
+}
+
+#[allow(dead_code)]
+fn test_similarly_named_function() {
+    fn drop<T>(_val: T) {}
+    drop(&SomeStruct); //OK; call to unrelated function which happens to have the same name
+    std::mem::drop(&SomeStruct);
+}
+
+#[derive(Copy, Clone)]
+pub struct Error;
+fn produce_half_owl_error() -> Result<(), Error> {
+    Ok(())
+}
+
+fn produce_half_owl_ok() -> Result<bool, ()> {
+    Ok(true)
+}
+
+#[allow(dead_code)]
+fn test_owl_result() -> Result<(), ()> {
+    produce_half_owl_error().map_err(|_| ())?;
+    produce_half_owl_ok().map(|_| ())?;
+    // the following should not be linted,
+    // we should not force users to use toilet closures
+    // to produce owl results when drop is more convenient
+    produce_half_owl_error().map_err(drop)?;
+    produce_half_owl_ok().map_err(drop)?;
+    Ok(())
+}
+
+#[allow(dead_code)]
+fn test_owl_result_2() -> Result<u8, ()> {
+    produce_half_owl_error().map_err(|_| ())?;
+    produce_half_owl_ok().map(|_| ())?;
+    // the following should not be linted,
+    // we should not force users to use toilet closures
+    // to produce owl results when drop is more convenient
+    produce_half_owl_error().map_err(drop)?;
+    produce_half_owl_ok().map(drop)?;
+    Ok(1)
+}
diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr
new file mode 100644
index 00000000000..35ae88b78a4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/drop_ref.stderr
@@ -0,0 +1,111 @@
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:9:5
+   |
+LL |     drop(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::drop-ref` implied by `-D warnings`
+note: argument has type `&SomeStruct`
+  --> $DIR/drop_ref.rs:9:10
+   |
+LL |     drop(&SomeStruct);
+   |          ^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:12:5
+   |
+LL |     drop(&owned1);
+   |     ^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/drop_ref.rs:12:10
+   |
+LL |     drop(&owned1);
+   |          ^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:13:5
+   |
+LL |     drop(&&owned1);
+   |     ^^^^^^^^^^^^^^
+   |
+note: argument has type `&&SomeStruct`
+  --> $DIR/drop_ref.rs:13:10
+   |
+LL |     drop(&&owned1);
+   |          ^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:14:5
+   |
+LL |     drop(&mut owned1);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&mut SomeStruct`
+  --> $DIR/drop_ref.rs:14:10
+   |
+LL |     drop(&mut owned1);
+   |          ^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:18:5
+   |
+LL |     drop(reference1);
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/drop_ref.rs:18:10
+   |
+LL |     drop(reference1);
+   |          ^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:21:5
+   |
+LL |     drop(reference2);
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&mut SomeStruct`
+  --> $DIR/drop_ref.rs:21:10
+   |
+LL |     drop(reference2);
+   |          ^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:24:5
+   |
+LL |     drop(reference3);
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/drop_ref.rs:24:10
+   |
+LL |     drop(reference3);
+   |          ^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:29:5
+   |
+LL |     drop(&val);
+   |     ^^^^^^^^^^
+   |
+note: argument has type `&T`
+  --> $DIR/drop_ref.rs:29:10
+   |
+LL |     drop(&val);
+   |          ^^^^
+
+error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
+  --> $DIR/drop_ref.rs:37:5
+   |
+LL |     std::mem::drop(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/drop_ref.rs:37:20
+   |
+LL |     std::mem::drop(&SomeStruct);
+   |                    ^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs
new file mode 100644
index 00000000000..54d748c7ce2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::duplicate_underscore_argument)]
+#[allow(dead_code, unused)]
+
+fn join_the_dark_side(darth: i32, _darth: i32) {}
+fn join_the_light_side(knight: i32, _master: i32) {} // the Force is strong with this one
+
+fn main() {
+    join_the_dark_side(0, 0);
+    join_the_light_side(0, 0);
+}
diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr
new file mode 100644
index 00000000000..f71614a5fd1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.stderr
@@ -0,0 +1,10 @@
+error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult
+  --> $DIR/duplicate_underscore_argument.rs:4:23
+   |
+LL | fn join_the_dark_side(darth: i32, _darth: i32) {}
+   |                       ^^^^^
+   |
+   = note: `-D clippy::duplicate-underscore-argument` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/duration_subsec.fixed b/src/tools/clippy/tests/ui/duration_subsec.fixed
new file mode 100644
index 00000000000..ee5c7863eff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duration_subsec.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::duration_subsec)]
+
+use std::time::Duration;
+
+fn main() {
+    let dur = Duration::new(5, 0);
+
+    let bad_millis_1 = dur.subsec_millis();
+    let bad_millis_2 = dur.subsec_millis();
+    let good_millis = dur.subsec_millis();
+    assert_eq!(bad_millis_1, good_millis);
+    assert_eq!(bad_millis_2, good_millis);
+
+    let bad_micros = dur.subsec_micros();
+    let good_micros = dur.subsec_micros();
+    assert_eq!(bad_micros, good_micros);
+
+    // Handle refs
+    let _ = (&dur).subsec_micros();
+
+    // Handle constants
+    const NANOS_IN_MICRO: u32 = 1_000;
+    let _ = dur.subsec_micros();
+
+    // Other literals aren't linted
+    let _ = dur.subsec_nanos() / 699;
+}
diff --git a/src/tools/clippy/tests/ui/duration_subsec.rs b/src/tools/clippy/tests/ui/duration_subsec.rs
new file mode 100644
index 00000000000..3c9d2a28621
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duration_subsec.rs
@@ -0,0 +1,29 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::duration_subsec)]
+
+use std::time::Duration;
+
+fn main() {
+    let dur = Duration::new(5, 0);
+
+    let bad_millis_1 = dur.subsec_micros() / 1_000;
+    let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
+    let good_millis = dur.subsec_millis();
+    assert_eq!(bad_millis_1, good_millis);
+    assert_eq!(bad_millis_2, good_millis);
+
+    let bad_micros = dur.subsec_nanos() / 1_000;
+    let good_micros = dur.subsec_micros();
+    assert_eq!(bad_micros, good_micros);
+
+    // Handle refs
+    let _ = (&dur).subsec_nanos() / 1_000;
+
+    // Handle constants
+    const NANOS_IN_MICRO: u32 = 1_000;
+    let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
+
+    // Other literals aren't linted
+    let _ = dur.subsec_nanos() / 699;
+}
diff --git a/src/tools/clippy/tests/ui/duration_subsec.stderr b/src/tools/clippy/tests/ui/duration_subsec.stderr
new file mode 100644
index 00000000000..bd8adc2c570
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duration_subsec.stderr
@@ -0,0 +1,34 @@
+error: Calling `subsec_millis()` is more concise than this calculation
+  --> $DIR/duration_subsec.rs:10:24
+   |
+LL |     let bad_millis_1 = dur.subsec_micros() / 1_000;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
+   |
+   = note: `-D clippy::duration-subsec` implied by `-D warnings`
+
+error: Calling `subsec_millis()` is more concise than this calculation
+  --> $DIR/duration_subsec.rs:11:24
+   |
+LL |     let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
+
+error: Calling `subsec_micros()` is more concise than this calculation
+  --> $DIR/duration_subsec.rs:16:22
+   |
+LL |     let bad_micros = dur.subsec_nanos() / 1_000;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
+
+error: Calling `subsec_micros()` is more concise than this calculation
+  --> $DIR/duration_subsec.rs:21:13
+   |
+LL |     let _ = (&dur).subsec_nanos() / 1_000;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()`
+
+error: Calling `subsec_micros()` is more concise than this calculation
+  --> $DIR/duration_subsec.rs:25:13
+   |
+LL |     let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/else_if_without_else.rs b/src/tools/clippy/tests/ui/else_if_without_else.rs
new file mode 100644
index 00000000000..879b3ac398e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/else_if_without_else.rs
@@ -0,0 +1,58 @@
+#![warn(clippy::all)]
+#![warn(clippy::else_if_without_else)]
+
+fn bla1() -> bool {
+    unimplemented!()
+}
+fn bla2() -> bool {
+    unimplemented!()
+}
+fn bla3() -> bool {
+    unimplemented!()
+}
+
+fn main() {
+    if bla1() {
+        println!("if");
+    }
+
+    if bla1() {
+        println!("if");
+    } else {
+        println!("else");
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if");
+    } else {
+        println!("else")
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else if bla3() {
+        println!("else if 2");
+    } else {
+        println!("else")
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        //~ ERROR else if without else
+        println!("else if");
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else if bla3() {
+        //~ ERROR else if without else
+        println!("else if 2");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/else_if_without_else.stderr b/src/tools/clippy/tests/ui/else_if_without_else.stderr
new file mode 100644
index 00000000000..6f47658cfb1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/else_if_without_else.stderr
@@ -0,0 +1,27 @@
+error: `if` expression with an `else if`, but without a final `else`
+  --> $DIR/else_if_without_else.rs:45:12
+   |
+LL |       } else if bla2() {
+   |  ____________^
+LL | |         //~ ERROR else if without else
+LL | |         println!("else if");
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::else-if-without-else` implied by `-D warnings`
+   = help: add an `else` block here
+
+error: `if` expression with an `else if`, but without a final `else`
+  --> $DIR/else_if_without_else.rs:54:12
+   |
+LL |       } else if bla3() {
+   |  ____________^
+LL | |         //~ ERROR else if without else
+LL | |         println!("else if 2");
+LL | |     }
+   | |_____^
+   |
+   = help: add an `else` block here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/empty_enum.rs b/src/tools/clippy/tests/ui/empty_enum.rs
new file mode 100644
index 00000000000..12428f29625
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum.rs
@@ -0,0 +1,6 @@
+#![allow(dead_code)]
+#![warn(clippy::empty_enum)]
+
+enum Empty {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum.stderr b/src/tools/clippy/tests/ui/empty_enum.stderr
new file mode 100644
index 00000000000..466dfbe7cee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum.stderr
@@ -0,0 +1,11 @@
+error: enum with no variants
+  --> $DIR/empty_enum.rs:4:1
+   |
+LL | enum Empty {}
+   | ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::empty-enum` implied by `-D warnings`
+   = help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
new file mode 100644
index 00000000000..5343dff9da1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
@@ -0,0 +1,96 @@
+#![warn(clippy::empty_line_after_outer_attr)]
+#![allow(clippy::assertions_on_constants)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+// This should produce a warning
+#[crate_type = "lib"]
+
+/// some comment
+fn with_one_newline_and_comment() { assert!(true) }
+
+// This should not produce a warning
+#[crate_type = "lib"]
+/// some comment
+fn with_no_newline_and_comment() { assert!(true) }
+
+
+// This should produce a warning
+#[crate_type = "lib"]
+
+fn with_one_newline() { assert!(true) }
+
+// This should produce a warning, too
+#[crate_type = "lib"]
+
+
+fn with_two_newlines() { assert!(true) }
+
+
+// This should produce a warning
+#[crate_type = "lib"]
+
+enum Baz {
+    One,
+    Two
+}
+
+// This should produce a warning
+#[crate_type = "lib"]
+
+struct Foo {
+    one: isize,
+    two: isize
+}
+
+// This should produce a warning
+#[crate_type = "lib"]
+
+mod foo {
+}
+
+/// This doc comment should not produce a warning
+
+/** This is also a doc comment and should not produce a warning
+ */
+
+// This should not produce a warning
+#[allow(non_camel_case_types)]
+#[allow(missing_docs)]
+#[allow(missing_docs)]
+fn three_attributes() { assert!(true) }
+
+// This should not produce a warning
+#[doc = "
+Returns the escaped value of the textual representation of
+
+"]
+pub fn function() -> bool {
+    true
+}
+
+// This should not produce a warning
+#[derive(Clone, Copy)]
+pub enum FooFighter {
+    Bar1,
+
+    Bar2,
+
+    Bar3,
+
+    Bar4
+}
+
+// This should not produce a warning because the empty line is inside a block comment
+#[crate_type = "lib"]
+/*
+
+*/
+pub struct S;
+
+// This should not produce a warning
+#[crate_type = "lib"]
+/* test */
+pub struct T;
+
+fn main() { }
diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr
new file mode 100644
index 00000000000..d8c9786541f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.stderr
@@ -0,0 +1,54 @@
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:7:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | /// some comment
+LL | | fn with_one_newline_and_comment() { assert!(true) }
+   | |_
+   |
+   = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
+
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:19:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | fn with_one_newline() { assert!(true) }
+   | |_
+
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:24:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | |
+LL | | fn with_two_newlines() { assert!(true) }
+   | |_
+
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:31:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | enum Baz {
+   | |_
+
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:39:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | struct Foo {
+   | |_
+
+error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
+  --> $DIR/empty_line_after_outer_attribute.rs:47:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | mod foo {
+   | |_
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/empty_loop.rs b/src/tools/clippy/tests/ui/empty_loop.rs
new file mode 100644
index 00000000000..8fd7697eb3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_loop.rs
@@ -0,0 +1,51 @@
+// aux-build:macro_rules.rs
+
+#![warn(clippy::empty_loop)]
+
+#[macro_use]
+extern crate macro_rules;
+
+fn should_trigger() {
+    loop {}
+    loop {
+        loop {}
+    }
+
+    'outer: loop {
+        'inner: loop {}
+    }
+}
+
+fn should_not_trigger() {
+    loop {
+        panic!("This is fine")
+    }
+    let ten_millis = std::time::Duration::from_millis(10);
+    loop {
+        std::thread::sleep(ten_millis)
+    }
+
+    #[allow(clippy::never_loop)]
+    'outer: loop {
+        'inner: loop {
+            break 'inner;
+        }
+        break 'outer;
+    }
+
+    // Make sure `allow` works for this lint
+    #[allow(clippy::empty_loop)]
+    loop {}
+
+    // We don't lint loops inside macros
+    macro_rules! foo {
+        () => {
+            loop {}
+        };
+    }
+
+    // We don't lint external macros
+    foofoo!()
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr
new file mode 100644
index 00000000000..e44c58ea770
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_loop.stderr
@@ -0,0 +1,22 @@
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:9:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::empty-loop` implied by `-D warnings`
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:11:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:15:9
+   |
+LL |         'inner: loop {}
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/entry_fixable.fixed b/src/tools/clippy/tests/ui/entry_fixable.fixed
new file mode 100644
index 00000000000..dcdaae7e724
--- /dev/null
+++ b/src/tools/clippy/tests/ui/entry_fixable.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(unused, clippy::needless_pass_by_value)]
+#![warn(clippy::map_entry)]
+
+use std::collections::{BTreeMap, HashMap};
+use std::hash::Hash;
+
+fn foo() {}
+
+fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    m.entry(k).or_insert(v);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry_fixable.rs b/src/tools/clippy/tests/ui/entry_fixable.rs
new file mode 100644
index 00000000000..55d5b21568d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/entry_fixable.rs
@@ -0,0 +1,17 @@
+// run-rustfix
+
+#![allow(unused, clippy::needless_pass_by_value)]
+#![warn(clippy::map_entry)]
+
+use std::collections::{BTreeMap, HashMap};
+use std::hash::Hash;
+
+fn foo() {}
+
+fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        m.insert(k, v);
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry_fixable.stderr b/src/tools/clippy/tests/ui/entry_fixable.stderr
new file mode 100644
index 00000000000..87403200ced
--- /dev/null
+++ b/src/tools/clippy/tests/ui/entry_fixable.stderr
@@ -0,0 +1,12 @@
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> $DIR/entry_fixable.rs:12:5
+   |
+LL | /     if !m.contains_key(&k) {
+LL | |         m.insert(k, v);
+LL | |     }
+   | |_____^ help: consider using: `m.entry(k).or_insert(v);`
+   |
+   = note: `-D clippy::map-entry` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.rs b/src/tools/clippy/tests/ui/entry_unfixable.rs
new file mode 100644
index 00000000000..f530fc023cf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/entry_unfixable.rs
@@ -0,0 +1,73 @@
+#![allow(unused, clippy::needless_pass_by_value)]
+#![warn(clippy::map_entry)]
+
+use std::collections::{BTreeMap, HashMap};
+use std::hash::Hash;
+
+fn foo() {}
+
+fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        m.insert(k, v)
+    } else {
+        None
+    };
+}
+
+fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    if m.contains_key(&k) {
+        None
+    } else {
+        m.insert(k, v)
+    };
+}
+
+fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        foo();
+        m.insert(k, v)
+    } else {
+        None
+    };
+}
+
+fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
+    if m.contains_key(&k) {
+        None
+    } else {
+        foo();
+        m.insert(k, v)
+    };
+}
+
+fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        foo();
+        m.insert(k, v)
+    } else {
+        None
+    };
+}
+
+// should not trigger
+fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) {
+    if !m.contains_key(&k) {
+        m.insert(o, v);
+    }
+}
+
+// should not trigger, because the one uses different HashMap from another one
+fn insert_from_different_map<K: Eq + Hash, V>(m: HashMap<K, V>, n: &mut HashMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        n.insert(k, v);
+    }
+}
+
+// should not trigger, because the one uses different HashMap from another one
+fn insert_from_different_map2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, n: &mut HashMap<K, V>, k: K, v: V) {
+    if !m.contains_key(&k) {
+        n.insert(k, v);
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.stderr b/src/tools/clippy/tests/ui/entry_unfixable.stderr
new file mode 100644
index 00000000000..e58c8d22dc4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/entry_unfixable.stderr
@@ -0,0 +1,57 @@
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> $DIR/entry_unfixable.rs:10:5
+   |
+LL | /     if !m.contains_key(&k) {
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ consider using `m.entry(k)`
+   |
+   = note: `-D clippy::map-entry` implied by `-D warnings`
+
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> $DIR/entry_unfixable.rs:18:5
+   |
+LL | /     if m.contains_key(&k) {
+LL | |         None
+LL | |     } else {
+LL | |         m.insert(k, v)
+LL | |     };
+   | |_____^ consider using `m.entry(k)`
+
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> $DIR/entry_unfixable.rs:26:5
+   |
+LL | /     if !m.contains_key(&k) {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ consider using `m.entry(k)`
+
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> $DIR/entry_unfixable.rs:35:5
+   |
+LL | /     if m.contains_key(&k) {
+LL | |         None
+LL | |     } else {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     };
+   | |_____^ consider using `m.entry(k)`
+
+error: usage of `contains_key` followed by `insert` on a `BTreeMap`
+  --> $DIR/entry_unfixable.rs:44:5
+   |
+LL | /     if !m.contains_key(&k) {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ consider using `m.entry(k)`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs
new file mode 100644
index 00000000000..7d6842f5b54
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs
@@ -0,0 +1,50 @@
+// ignore-x86
+
+#![warn(clippy::enum_clike_unportable_variant)]
+#![allow(unused, non_upper_case_globals)]
+
+#[repr(usize)]
+enum NonPortable {
+    X = 0x1_0000_0000,
+    Y = 0,
+    Z = 0x7FFF_FFFF,
+    A = 0xFFFF_FFFF,
+}
+
+enum NonPortableNoHint {
+    X = 0x1_0000_0000,
+    Y = 0,
+    Z = 0x7FFF_FFFF,
+    A = 0xFFFF_FFFF,
+}
+
+#[repr(isize)]
+enum NonPortableSigned {
+    X = -1,
+    Y = 0x7FFF_FFFF,
+    Z = 0xFFFF_FFFF,
+    A = 0x1_0000_0000,
+    B = i32::MIN as isize,
+    C = (i32::MIN as isize) - 1,
+}
+
+enum NonPortableSignedNoHint {
+    X = -1,
+    Y = 0x7FFF_FFFF,
+    Z = 0xFFFF_FFFF,
+    A = 0x1_0000_0000,
+}
+
+#[repr(usize)]
+enum NonPortable2 {
+    X = <usize as Trait>::Number,
+    Y = 0,
+}
+
+trait Trait {
+    const Number: usize = 0x1_0000_0000;
+}
+
+impl Trait for usize {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
new file mode 100644
index 00000000000..71f3f5e083e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
@@ -0,0 +1,58 @@
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:8:5
+   |
+LL |     X = 0x1_0000_0000,
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings`
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:15:5
+   |
+LL |     X = 0x1_0000_0000,
+   |     ^^^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:18:5
+   |
+LL |     A = 0xFFFF_FFFF,
+   |     ^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:25:5
+   |
+LL |     Z = 0xFFFF_FFFF,
+   |     ^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:26:5
+   |
+LL |     A = 0x1_0000_0000,
+   |     ^^^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:28:5
+   |
+LL |     C = (i32::MIN as isize) - 1,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:34:5
+   |
+LL |     Z = 0xFFFF_FFFF,
+   |     ^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:35:5
+   |
+LL |     A = 0x1_0000_0000,
+   |     ^^^^^^^^^^^^^^^^^
+
+error: Clike enum variant discriminant is not portable to 32-bit targets
+  --> $DIR/enum_clike_unportable_variant.rs:40:5
+   |
+LL |     X = <usize as Trait>::Number,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/enum_glob_use.fixed b/src/tools/clippy/tests/ui/enum_glob_use.fixed
new file mode 100644
index 00000000000..a98216758bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_glob_use.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+
+#![warn(clippy::enum_glob_use)]
+#![allow(unused)]
+#![warn(unused_imports)]
+
+use std::cmp::Ordering::Less;
+
+enum Enum {
+    Foo,
+}
+
+use self::Enum::Foo;
+
+mod in_fn_test {
+    fn blarg() {
+        use crate::Enum::Foo;
+
+        let _ = Foo;
+    }
+}
+
+mod blurg {
+    pub use std::cmp::Ordering::*; // ok, re-export
+}
+
+fn main() {
+    let _ = Foo;
+    let _ = Less;
+}
diff --git a/src/tools/clippy/tests/ui/enum_glob_use.rs b/src/tools/clippy/tests/ui/enum_glob_use.rs
new file mode 100644
index 00000000000..5d929c9731d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_glob_use.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+
+#![warn(clippy::enum_glob_use)]
+#![allow(unused)]
+#![warn(unused_imports)]
+
+use std::cmp::Ordering::*;
+
+enum Enum {
+    Foo,
+}
+
+use self::Enum::*;
+
+mod in_fn_test {
+    fn blarg() {
+        use crate::Enum::*;
+
+        let _ = Foo;
+    }
+}
+
+mod blurg {
+    pub use std::cmp::Ordering::*; // ok, re-export
+}
+
+fn main() {
+    let _ = Foo;
+    let _ = Less;
+}
diff --git a/src/tools/clippy/tests/ui/enum_glob_use.stderr b/src/tools/clippy/tests/ui/enum_glob_use.stderr
new file mode 100644
index 00000000000..69531aed39b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_glob_use.stderr
@@ -0,0 +1,22 @@
+error: usage of wildcard import for enum variants
+  --> $DIR/enum_glob_use.rs:7:5
+   |
+LL | use std::cmp::Ordering::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::cmp::Ordering::Less`
+   |
+   = note: `-D clippy::enum-glob-use` implied by `-D warnings`
+
+error: usage of wildcard import for enum variants
+  --> $DIR/enum_glob_use.rs:13:5
+   |
+LL | use self::Enum::*;
+   |     ^^^^^^^^^^^^^ help: try: `self::Enum::Foo`
+
+error: usage of wildcard import for enum variants
+  --> $DIR/enum_glob_use.rs:17:13
+   |
+LL |         use crate::Enum::*;
+   |             ^^^^^^^^^^^^^^ help: try: `crate::Enum::Foo`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
new file mode 100644
index 00000000000..01774a2a984
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -0,0 +1,136 @@
+#![feature(non_ascii_idents)]
+#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![allow(non_camel_case_types)]
+
+enum FakeCallType {
+    CALL,
+    CREATE,
+}
+
+enum FakeCallType2 {
+    CALL,
+    CREATELL,
+}
+
+enum Foo {
+    cFoo,
+    cBar,
+    cBaz,
+}
+
+enum Fooo {
+    cFoo, // no error, threshold is 3 variants by default
+    cBar,
+}
+
+enum Food {
+    FoodGood,
+    FoodMiddle,
+    FoodBad,
+}
+
+enum Stuff {
+    StuffBad, // no error
+}
+
+enum BadCallType {
+    CallTypeCall,
+    CallTypeCreate,
+    CallTypeDestroy,
+}
+
+enum TwoCallType {
+    // no error
+    CallTypeCall,
+    CallTypeCreate,
+}
+
+enum Consts {
+    ConstantInt,
+    ConstantCake,
+    ConstantLie,
+}
+
+enum Two {
+    // no error here
+    ConstantInt,
+    ConstantInfer,
+}
+
+enum Something {
+    CCall,
+    CCreate,
+    CCryogenize,
+}
+
+enum Seal {
+    With,
+    Without,
+}
+
+enum Seall {
+    With,
+    WithOut,
+    Withbroken,
+}
+
+enum Sealll {
+    With,
+    WithOut,
+}
+
+enum Seallll {
+    WithOutCake,
+    WithOutTea,
+    WithOut,
+}
+
+enum NonCaps {
+    Prefix的,
+    PrefixTea,
+    PrefixCake,
+}
+
+pub enum PubSeall {
+    WithOutCake,
+    WithOutTea,
+    WithOut,
+}
+
+#[allow(clippy::pub_enum_variant_names)]
+mod allowed {
+    pub enum PubAllowed {
+        SomeThis,
+        SomeThat,
+        SomeOtherWhat,
+    }
+}
+
+// should not lint
+enum Pat {
+    Foo,
+    Bar,
+    Path,
+}
+
+// should not lint
+enum N {
+    Pos,
+    Neg,
+    Float,
+}
+
+// should not lint
+enum Peek {
+    Peek1,
+    Peek2,
+    Peek3,
+}
+
+// should not lint
+pub enum NetworkLayer {
+    Layer2,
+    Layer3,
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr
new file mode 100644
index 00000000000..2835391de7f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/enum_variants.stderr
@@ -0,0 +1,101 @@
+error: Variant name ends with the enum's name
+  --> $DIR/enum_variants.rs:16:5
+   |
+LL |     cFoo,
+   |     ^^^^
+   |
+   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+
+error: Variant name starts with the enum's name
+  --> $DIR/enum_variants.rs:27:5
+   |
+LL |     FoodGood,
+   |     ^^^^^^^^
+
+error: Variant name starts with the enum's name
+  --> $DIR/enum_variants.rs:28:5
+   |
+LL |     FoodMiddle,
+   |     ^^^^^^^^^^
+
+error: Variant name starts with the enum's name
+  --> $DIR/enum_variants.rs:29:5
+   |
+LL |     FoodBad,
+   |     ^^^^^^^
+
+error: All variants have the same prefix: `Food`
+  --> $DIR/enum_variants.rs:26:1
+   |
+LL | / enum Food {
+LL | |     FoodGood,
+LL | |     FoodMiddle,
+LL | |     FoodBad,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: All variants have the same prefix: `CallType`
+  --> $DIR/enum_variants.rs:36:1
+   |
+LL | / enum BadCallType {
+LL | |     CallTypeCall,
+LL | |     CallTypeCreate,
+LL | |     CallTypeDestroy,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: All variants have the same prefix: `Constant`
+  --> $DIR/enum_variants.rs:48:1
+   |
+LL | / enum Consts {
+LL | |     ConstantInt,
+LL | |     ConstantCake,
+LL | |     ConstantLie,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: All variants have the same prefix: `With`
+  --> $DIR/enum_variants.rs:82:1
+   |
+LL | / enum Seallll {
+LL | |     WithOutCake,
+LL | |     WithOutTea,
+LL | |     WithOut,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: All variants have the same prefix: `Prefix`
+  --> $DIR/enum_variants.rs:88:1
+   |
+LL | / enum NonCaps {
+LL | |     Prefix的,
+LL | |     PrefixTea,
+LL | |     PrefixCake,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: All variants have the same prefix: `With`
+  --> $DIR/enum_variants.rs:94:1
+   |
+LL | / pub enum PubSeall {
+LL | |     WithOutCake,
+LL | |     WithOutTea,
+LL | |     WithOut,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eq_op.rs b/src/tools/clippy/tests/ui/eq_op.rs
new file mode 100644
index 00000000000..272b0900a31
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eq_op.rs
@@ -0,0 +1,87 @@
+// does not test any rustfixable lints
+
+#[rustfmt::skip]
+#[warn(clippy::eq_op)]
+#[allow(clippy::identity_op, clippy::double_parens, clippy::many_single_char_names)]
+#[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
+#[allow(clippy::nonminimal_bool)]
+#[allow(unused)]
+fn main() {
+    // simple values and comparisons
+    1 == 1;
+    "no" == "no";
+    // even though I agree that no means no ;-)
+    false != false;
+    1.5 < 1.5;
+    1u64 >= 1u64;
+
+    // casts, methods, parentheses
+    (1 as u64) & (1 as u64);
+    1 ^ ((((((1))))));
+
+    // unary and binary operators
+    (-(2) < -(2));
+    ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+    (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
+
+    // various other things
+    ([1] != [1]);
+    ((1, 2) != (1, 2));
+    vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros
+
+    // const folding
+    1 + 1 == 2;
+    1 - 1 == 0;
+
+    1 - 1;
+    1 / 1;
+    true && true;
+
+    true || true;
+
+
+    let a: u32 = 0;
+    let b: u32 = 0;
+
+    a == b && b == a;
+    a != b && b != a;
+    a < b && b > a;
+    a <= b && b >= a;
+
+    let mut a = vec![1];
+    a == a;
+    2*a.len() == 2*a.len(); // ok, functions
+    a.pop() == a.pop(); // ok, functions
+
+    check_ignore_macro();
+
+    // named constants
+    const A: u32 = 10;
+    const B: u32 = 10;
+    const C: u32 = A / B; // ok, different named constants
+    const D: u32 = A / A;
+}
+
+#[rustfmt::skip]
+macro_rules! check_if_named_foo {
+    ($expression:expr) => (
+        if stringify!($expression) == "foo" {
+            println!("foo!");
+        } else {
+            println!("not foo.");
+        }
+    )
+}
+
+macro_rules! bool_macro {
+    ($expression:expr) => {
+        true
+    };
+}
+
+#[allow(clippy::short_circuit_statement)]
+fn check_ignore_macro() {
+    check_if_named_foo!(foo);
+    // checks if the lint ignores macros with `!` operator
+    !bool_macro!(1) && !bool_macro!("");
+}
diff --git a/src/tools/clippy/tests/ui/eq_op.stderr b/src/tools/clippy/tests/ui/eq_op.stderr
new file mode 100644
index 00000000000..5b80e6078ee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eq_op.stderr
@@ -0,0 +1,166 @@
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:11:5
+   |
+LL |     1 == 1;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::eq-op` implied by `-D warnings`
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:12:5
+   |
+LL |     "no" == "no";
+   |     ^^^^^^^^^^^^
+
+error: equal expressions as operands to `!=`
+  --> $DIR/eq_op.rs:14:5
+   |
+LL |     false != false;
+   |     ^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `<`
+  --> $DIR/eq_op.rs:15:5
+   |
+LL |     1.5 < 1.5;
+   |     ^^^^^^^^^
+
+error: equal expressions as operands to `>=`
+  --> $DIR/eq_op.rs:16:5
+   |
+LL |     1u64 >= 1u64;
+   |     ^^^^^^^^^^^^
+
+error: equal expressions as operands to `&`
+  --> $DIR/eq_op.rs:19:5
+   |
+LL |     (1 as u64) & (1 as u64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `^`
+  --> $DIR/eq_op.rs:20:5
+   |
+LL |     1 ^ ((((((1))))));
+   |     ^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `<`
+  --> $DIR/eq_op.rs:23:5
+   |
+LL |     (-(2) < -(2));
+   |     ^^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:24:5
+   |
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `&`
+  --> $DIR/eq_op.rs:24:6
+   |
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |      ^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `&`
+  --> $DIR/eq_op.rs:24:27
+   |
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |                           ^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:25:5
+   |
+LL |     (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `!=`
+  --> $DIR/eq_op.rs:28:5
+   |
+LL |     ([1] != [1]);
+   |     ^^^^^^^^^^^^
+
+error: equal expressions as operands to `!=`
+  --> $DIR/eq_op.rs:29:5
+   |
+LL |     ((1, 2) != (1, 2));
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:33:5
+   |
+LL |     1 + 1 == 2;
+   |     ^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:34:5
+   |
+LL |     1 - 1 == 0;
+   |     ^^^^^^^^^^
+
+error: equal expressions as operands to `-`
+  --> $DIR/eq_op.rs:34:5
+   |
+LL |     1 - 1 == 0;
+   |     ^^^^^
+
+error: equal expressions as operands to `-`
+  --> $DIR/eq_op.rs:36:5
+   |
+LL |     1 - 1;
+   |     ^^^^^
+
+error: equal expressions as operands to `/`
+  --> $DIR/eq_op.rs:37:5
+   |
+LL |     1 / 1;
+   |     ^^^^^
+
+error: equal expressions as operands to `&&`
+  --> $DIR/eq_op.rs:38:5
+   |
+LL |     true && true;
+   |     ^^^^^^^^^^^^
+
+error: equal expressions as operands to `||`
+  --> $DIR/eq_op.rs:40:5
+   |
+LL |     true || true;
+   |     ^^^^^^^^^^^^
+
+error: equal expressions as operands to `&&`
+  --> $DIR/eq_op.rs:46:5
+   |
+LL |     a == b && b == a;
+   |     ^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `&&`
+  --> $DIR/eq_op.rs:47:5
+   |
+LL |     a != b && b != a;
+   |     ^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `&&`
+  --> $DIR/eq_op.rs:48:5
+   |
+LL |     a < b && b > a;
+   |     ^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `&&`
+  --> $DIR/eq_op.rs:49:5
+   |
+LL |     a <= b && b >= a;
+   |     ^^^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/eq_op.rs:52:5
+   |
+LL |     a == a;
+   |     ^^^^^^
+
+error: equal expressions as operands to `/`
+  --> $DIR/eq_op.rs:62:20
+   |
+LL |     const D: u32 = A / A;
+   |                    ^^^^^
+
+error: aborting due to 27 previous errors
+
diff --git a/src/tools/clippy/tests/ui/erasing_op.rs b/src/tools/clippy/tests/ui/erasing_op.rs
new file mode 100644
index 00000000000..1540062a4bc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/erasing_op.rs
@@ -0,0 +1,9 @@
+#[allow(clippy::no_effect)]
+#[warn(clippy::erasing_op)]
+fn main() {
+    let x: u8 = 0;
+
+    x * 0;
+    0 & x;
+    0 / x;
+}
diff --git a/src/tools/clippy/tests/ui/erasing_op.stderr b/src/tools/clippy/tests/ui/erasing_op.stderr
new file mode 100644
index 00000000000..e54ce85f98e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/erasing_op.stderr
@@ -0,0 +1,22 @@
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/erasing_op.rs:6:5
+   |
+LL |     x * 0;
+   |     ^^^^^
+   |
+   = note: `-D clippy::erasing-op` implied by `-D warnings`
+
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/erasing_op.rs:7:5
+   |
+LL |     0 & x;
+   |     ^^^^^
+
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/erasing_op.rs:8:5
+   |
+LL |     0 / x;
+   |     ^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/escape_analysis.rs
new file mode 100644
index 00000000000..c0a52d832c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/escape_analysis.rs
@@ -0,0 +1,176 @@
+#![feature(box_syntax)]
+#![allow(
+    clippy::borrowed_box,
+    clippy::needless_pass_by_value,
+    clippy::unused_unit,
+    clippy::redundant_clone,
+    clippy::match_single_binding
+)]
+#![warn(clippy::boxed_local)]
+
+#[derive(Clone)]
+struct A;
+
+impl A {
+    fn foo(&self) {}
+}
+
+trait Z {
+    fn bar(&self);
+}
+
+impl Z for A {
+    fn bar(&self) {
+        //nothing
+    }
+}
+
+fn main() {}
+
+fn ok_box_trait(boxed_trait: &Box<dyn Z>) {
+    let boxed_local = boxed_trait;
+    // done
+}
+
+fn warn_call() {
+    let x = box A;
+    x.foo();
+}
+
+fn warn_arg(x: Box<A>) {
+    x.foo();
+}
+
+fn nowarn_closure_arg() {
+    let x = Some(box A);
+    x.map_or((), |x| take_ref(&x));
+}
+
+fn warn_rename_call() {
+    let x = box A;
+
+    let y = x;
+    y.foo(); // via autoderef
+}
+
+fn warn_notuse() {
+    let bz = box A;
+}
+
+fn warn_pass() {
+    let bz = box A;
+    take_ref(&bz); // via deref coercion
+}
+
+fn nowarn_return() -> Box<A> {
+    box A // moved out, "escapes"
+}
+
+fn nowarn_move() {
+    let bx = box A;
+    drop(bx) // moved in, "escapes"
+}
+fn nowarn_call() {
+    let bx = box A;
+    bx.clone(); // method only available to Box, not via autoderef
+}
+
+fn nowarn_pass() {
+    let bx = box A;
+    take_box(&bx); // fn needs &Box
+}
+
+fn take_box(x: &Box<A>) {}
+fn take_ref(x: &A) {}
+
+fn nowarn_ref_take() {
+    // false positive, should actually warn
+    let x = box A;
+    let y = &x;
+    take_box(y);
+}
+
+fn nowarn_match() {
+    let x = box A; // moved into a match
+    match x {
+        y => drop(y),
+    }
+}
+
+fn warn_match() {
+    let x = box A;
+    match &x {
+        // not moved
+        ref y => (),
+    }
+}
+
+fn nowarn_large_array() {
+    // should not warn, is large array
+    // and should not be on stack
+    let x = box [1; 10000];
+    match &x {
+        // not moved
+        ref y => (),
+    }
+}
+
+/// ICE regression test
+pub trait Foo {
+    type Item;
+}
+
+impl<'a> Foo for &'a () {
+    type Item = ();
+}
+
+pub struct PeekableSeekable<I: Foo> {
+    _peeked: I::Item,
+}
+
+pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
+
+/// Regression for #916, #1123
+///
+/// This shouldn't warn for `boxed_local`as the implementation of a trait
+/// can't change much about the trait definition.
+trait BoxedAction {
+    fn do_sth(self: Box<Self>);
+}
+
+impl BoxedAction for u64 {
+    fn do_sth(self: Box<Self>) {
+        println!("{}", *self)
+    }
+}
+
+/// Regression for #1478
+///
+/// This shouldn't warn for `boxed_local`as self itself is a box type.
+trait MyTrait {
+    fn do_sth(self);
+}
+
+impl<T> MyTrait for Box<T> {
+    fn do_sth(self) {}
+}
+
+// Issue #3739 - capture in closures
+mod issue_3739 {
+    use super::A;
+
+    fn consume<T>(_: T) {}
+    fn borrow<T>(_: &T) {}
+
+    fn closure_consume(x: Box<A>) {
+        let _ = move || {
+            consume(x);
+        };
+    }
+
+    fn closure_borrow(x: Box<A>) {
+        let _ = || {
+            borrow(&x);
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/escape_analysis.stderr b/src/tools/clippy/tests/ui/escape_analysis.stderr
new file mode 100644
index 00000000000..c86a769a3da
--- /dev/null
+++ b/src/tools/clippy/tests/ui/escape_analysis.stderr
@@ -0,0 +1,16 @@
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:40:13
+   |
+LL | fn warn_arg(x: Box<A>) {
+   |             ^
+   |
+   = note: `-D clippy::boxed-local` implied by `-D warnings`
+
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:131:12
+   |
+LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
+   |            ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
new file mode 100644
index 00000000000..1b34c2f74eb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -0,0 +1,204 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::no_effect,
+    clippy::redundant_closure_call,
+    clippy::many_single_char_names,
+    clippy::needless_pass_by_value,
+    clippy::option_map_unit_fn
+)]
+#![warn(
+    clippy::redundant_closure,
+    clippy::redundant_closure_for_method_calls,
+    clippy::needless_borrow
+)]
+
+use std::path::PathBuf;
+
+fn main() {
+    let a = Some(1u8).map(foo);
+    meta(foo);
+    let c = Some(1u8).map(|a| {1+2; foo}(a));
+    let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
+    all(&[1, 2, 3], &2, |x, y| below(x, y)); //is adjusted
+    unsafe {
+        Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
+    }
+
+    // See #815
+    let e = Some(1u8).map(|a| divergent(a));
+    let e = Some(1u8).map(generic);
+    let e = Some(1u8).map(generic);
+    // See #515
+    let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
+        Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+}
+
+trait TestTrait {
+    fn trait_foo(self) -> bool;
+    fn trait_foo_ref(&self) -> bool;
+}
+
+struct TestStruct<'a> {
+    some_ref: &'a i32,
+}
+
+impl<'a> TestStruct<'a> {
+    fn foo(self) -> bool {
+        false
+    }
+    unsafe fn foo_unsafe(self) -> bool {
+        true
+    }
+}
+
+impl<'a> TestTrait for TestStruct<'a> {
+    fn trait_foo(self) -> bool {
+        false
+    }
+    fn trait_foo_ref(&self) -> bool {
+        false
+    }
+}
+
+impl<'a> std::ops::Deref for TestStruct<'a> {
+    type Target = char;
+    fn deref(&self) -> &char {
+        &'a'
+    }
+}
+
+fn test_redundant_closures_containing_method_calls() {
+    let i = 10;
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    unsafe {
+        let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
+    }
+    let e = Some("str").map(std::string::ToString::to_string);
+    let e = Some("str").map(str::to_string);
+    let e = Some('a').map(char::to_uppercase);
+    let e = Some('a').map(char::to_uppercase);
+    let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let p = Some(PathBuf::new());
+    let e = p.as_ref().and_then(|s| s.to_str());
+    let c = Some(TestStruct { some_ref: &i })
+        .as_ref()
+        .map(|c| c.to_ascii_uppercase());
+
+    fn test_different_borrow_levels<T>(t: &[&T])
+    where
+        T: TestTrait,
+    {
+        t.iter().filter(|x| x.trait_foo_ref());
+        t.iter().map(|x| x.trait_foo_ref());
+    }
+
+    let mut some = Some(|x| x * x);
+    let arr = [Ok(1), Err(2)];
+    let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
+}
+
+struct Thunk<T>(Box<dyn FnMut() -> T>);
+
+impl<T> Thunk<T> {
+    fn new<F: 'static + FnOnce() -> T>(f: F) -> Thunk<T> {
+        let mut option = Some(f);
+        // This should not trigger redundant_closure (#1439)
+        Thunk(Box::new(move || option.take().unwrap()()))
+    }
+
+    fn unwrap(self) -> T {
+        let Thunk(mut f) = self;
+        f()
+    }
+}
+
+fn foobar() {
+    let thunk = Thunk::new(|| println!("Hello, world!"));
+    thunk.unwrap()
+}
+
+fn meta<F>(f: F)
+where
+    F: Fn(u8),
+{
+    f(1u8)
+}
+
+fn foo(_: u8) {}
+
+fn foo2(_: u8) -> u8 {
+    1u8
+}
+
+fn all<X, F>(x: &[X], y: &X, f: F) -> bool
+where
+    F: Fn(&X, &X) -> bool,
+{
+    x.iter().all(|e| f(e, y))
+}
+
+fn below(x: &u8, y: &u8) -> bool {
+    x < y
+}
+
+unsafe fn unsafe_fn(_: u8) {}
+
+fn divergent(_: u8) -> ! {
+    unimplemented!()
+}
+
+fn generic<T>(_: T) -> u8 {
+    0
+}
+
+fn passes_fn_mut(mut x: Box<dyn FnMut()>) {
+    requires_fn_once(|| x());
+}
+fn requires_fn_once<T: FnOnce()>(_: T) {}
+
+fn test_redundant_closure_with_function_pointer() {
+    type FnPtrType = fn(u8);
+    let foo_ptr: FnPtrType = foo;
+    let a = Some(1u8).map(foo_ptr);
+}
+
+fn test_redundant_closure_with_another_closure() {
+    let closure = |a| println!("{}", a);
+    let a = Some(1u8).map(closure);
+}
+
+fn make_lazy(f: impl Fn() -> fn(u8) -> u8) -> impl Fn(u8) -> u8 {
+    // Currently f is called when result of make_lazy is called.
+    // If the closure is removed, f will be called when make_lazy itself is
+    // called. This changes semantics, so the closure must stay.
+    Box::new(move |x| f()(x))
+}
+
+fn call<F: FnOnce(&mut String) -> String>(f: F) -> String {
+    f(&mut "Hello".to_owned())
+}
+fn test_difference_in_mutability() {
+    call(|s| s.clone());
+}
+
+struct Bar;
+impl std::ops::Deref for Bar {
+    type Target = str;
+    fn deref(&self) -> &str {
+        "hi"
+    }
+}
+
+fn test_deref_with_trait_method() {
+    let _ = [Bar].iter().map(|s| s.to_string()).collect::<Vec<_>>();
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
new file mode 100644
index 00000000000..4f050bd8479
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -0,0 +1,204 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::no_effect,
+    clippy::redundant_closure_call,
+    clippy::many_single_char_names,
+    clippy::needless_pass_by_value,
+    clippy::option_map_unit_fn
+)]
+#![warn(
+    clippy::redundant_closure,
+    clippy::redundant_closure_for_method_calls,
+    clippy::needless_borrow
+)]
+
+use std::path::PathBuf;
+
+fn main() {
+    let a = Some(1u8).map(|a| foo(a));
+    meta(|a| foo(a));
+    let c = Some(1u8).map(|a| {1+2; foo}(a));
+    let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
+    all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
+    unsafe {
+        Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
+    }
+
+    // See #815
+    let e = Some(1u8).map(|a| divergent(a));
+    let e = Some(1u8).map(|a| generic(a));
+    let e = Some(1u8).map(generic);
+    // See #515
+    let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
+        Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+}
+
+trait TestTrait {
+    fn trait_foo(self) -> bool;
+    fn trait_foo_ref(&self) -> bool;
+}
+
+struct TestStruct<'a> {
+    some_ref: &'a i32,
+}
+
+impl<'a> TestStruct<'a> {
+    fn foo(self) -> bool {
+        false
+    }
+    unsafe fn foo_unsafe(self) -> bool {
+        true
+    }
+}
+
+impl<'a> TestTrait for TestStruct<'a> {
+    fn trait_foo(self) -> bool {
+        false
+    }
+    fn trait_foo_ref(&self) -> bool {
+        false
+    }
+}
+
+impl<'a> std::ops::Deref for TestStruct<'a> {
+    type Target = char;
+    fn deref(&self) -> &char {
+        &'a'
+    }
+}
+
+fn test_redundant_closures_containing_method_calls() {
+    let i = 10;
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    unsafe {
+        let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
+    }
+    let e = Some("str").map(|s| s.to_string());
+    let e = Some("str").map(str::to_string);
+    let e = Some('a').map(|s| s.to_uppercase());
+    let e = Some('a').map(char::to_uppercase);
+    let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let p = Some(PathBuf::new());
+    let e = p.as_ref().and_then(|s| s.to_str());
+    let c = Some(TestStruct { some_ref: &i })
+        .as_ref()
+        .map(|c| c.to_ascii_uppercase());
+
+    fn test_different_borrow_levels<T>(t: &[&T])
+    where
+        T: TestTrait,
+    {
+        t.iter().filter(|x| x.trait_foo_ref());
+        t.iter().map(|x| x.trait_foo_ref());
+    }
+
+    let mut some = Some(|x| x * x);
+    let arr = [Ok(1), Err(2)];
+    let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
+}
+
+struct Thunk<T>(Box<dyn FnMut() -> T>);
+
+impl<T> Thunk<T> {
+    fn new<F: 'static + FnOnce() -> T>(f: F) -> Thunk<T> {
+        let mut option = Some(f);
+        // This should not trigger redundant_closure (#1439)
+        Thunk(Box::new(move || option.take().unwrap()()))
+    }
+
+    fn unwrap(self) -> T {
+        let Thunk(mut f) = self;
+        f()
+    }
+}
+
+fn foobar() {
+    let thunk = Thunk::new(|| println!("Hello, world!"));
+    thunk.unwrap()
+}
+
+fn meta<F>(f: F)
+where
+    F: Fn(u8),
+{
+    f(1u8)
+}
+
+fn foo(_: u8) {}
+
+fn foo2(_: u8) -> u8 {
+    1u8
+}
+
+fn all<X, F>(x: &[X], y: &X, f: F) -> bool
+where
+    F: Fn(&X, &X) -> bool,
+{
+    x.iter().all(|e| f(e, y))
+}
+
+fn below(x: &u8, y: &u8) -> bool {
+    x < y
+}
+
+unsafe fn unsafe_fn(_: u8) {}
+
+fn divergent(_: u8) -> ! {
+    unimplemented!()
+}
+
+fn generic<T>(_: T) -> u8 {
+    0
+}
+
+fn passes_fn_mut(mut x: Box<dyn FnMut()>) {
+    requires_fn_once(|| x());
+}
+fn requires_fn_once<T: FnOnce()>(_: T) {}
+
+fn test_redundant_closure_with_function_pointer() {
+    type FnPtrType = fn(u8);
+    let foo_ptr: FnPtrType = foo;
+    let a = Some(1u8).map(|a| foo_ptr(a));
+}
+
+fn test_redundant_closure_with_another_closure() {
+    let closure = |a| println!("{}", a);
+    let a = Some(1u8).map(|a| closure(a));
+}
+
+fn make_lazy(f: impl Fn() -> fn(u8) -> u8) -> impl Fn(u8) -> u8 {
+    // Currently f is called when result of make_lazy is called.
+    // If the closure is removed, f will be called when make_lazy itself is
+    // called. This changes semantics, so the closure must stay.
+    Box::new(move |x| f()(x))
+}
+
+fn call<F: FnOnce(&mut String) -> String>(f: F) -> String {
+    f(&mut "Hello".to_owned())
+}
+fn test_difference_in_mutability() {
+    call(|s| s.clone());
+}
+
+struct Bar;
+impl std::ops::Deref for Bar {
+    type Target = str;
+    fn deref(&self) -> &str {
+        "hi"
+    }
+}
+
+fn test_deref_with_trait_method() {
+    let _ = [Bar].iter().map(|s| s.to_string()).collect::<Vec<_>>();
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
new file mode 100644
index 00000000000..c4713ca8083
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -0,0 +1,80 @@
+error: redundant closure found
+  --> $DIR/eta.rs:20:27
+   |
+LL |     let a = Some(1u8).map(|a| foo(a));
+   |                           ^^^^^^^^^^ help: remove closure as shown: `foo`
+   |
+   = note: `-D clippy::redundant-closure` implied by `-D warnings`
+
+error: redundant closure found
+  --> $DIR/eta.rs:21:10
+   |
+LL |     meta(|a| foo(a));
+   |          ^^^^^^^^^^ help: remove closure as shown: `foo`
+
+error: this expression borrows a reference that is immediately dereferenced by the compiler
+  --> $DIR/eta.rs:24:21
+   |
+LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
+   |                     ^^^ help: change this to: `&2`
+   |
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: redundant closure found
+  --> $DIR/eta.rs:31:27
+   |
+LL |     let e = Some(1u8).map(|a| generic(a));
+   |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `generic`
+
+error: redundant closure found
+  --> $DIR/eta.rs:74:51
+   |
+LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
+   |                                                   ^^^^^^^^^^^ help: remove closure as shown: `TestStruct::foo`
+   |
+   = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
+
+error: redundant closure found
+  --> $DIR/eta.rs:76:51
+   |
+LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
+   |                                                   ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `TestTrait::trait_foo`
+
+error: redundant closure found
+  --> $DIR/eta.rs:79:42
+   |
+LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
+   |                                          ^^^^^^^^^^^^^ help: remove closure as shown: `std::vec::Vec::clear`
+
+error: redundant closure found
+  --> $DIR/eta.rs:84:29
+   |
+LL |     let e = Some("str").map(|s| s.to_string());
+   |                             ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string`
+
+error: redundant closure found
+  --> $DIR/eta.rs:86:27
+   |
+LL |     let e = Some('a').map(|s| s.to_uppercase());
+   |                           ^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_uppercase`
+
+error: redundant closure found
+  --> $DIR/eta.rs:89:65
+   |
+LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
+   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase`
+
+error: redundant closure found
+  --> $DIR/eta.rs:172:27
+   |
+LL |     let a = Some(1u8).map(|a| foo_ptr(a));
+   |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `foo_ptr`
+
+error: redundant closure found
+  --> $DIR/eta.rs:177:27
+   |
+LL |     let a = Some(1u8).map(|a| closure(a));
+   |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `closure`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.rs b/src/tools/clippy/tests/ui/eval_order_dependence.rs
new file mode 100644
index 00000000000..d806bc6d401
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eval_order_dependence.rs
@@ -0,0 +1,109 @@
+#[warn(clippy::eval_order_dependence)]
+#[allow(
+    unused_assignments,
+    unused_variables,
+    clippy::many_single_char_names,
+    clippy::no_effect,
+    dead_code,
+    clippy::blacklisted_name
+)]
+fn main() {
+    let mut x = 0;
+    let a = {
+        x = 1;
+        1
+    } + x;
+
+    // Example from iss#277
+    x += {
+        x = 20;
+        2
+    };
+
+    // Does it work in weird places?
+    // ...in the base for a struct expression?
+    struct Foo {
+        a: i32,
+        b: i32,
+    };
+    let base = Foo { a: 4, b: 5 };
+    let foo = Foo {
+        a: x,
+        ..{
+            x = 6;
+            base
+        }
+    };
+    // ...inside a closure?
+    let closure = || {
+        let mut x = 0;
+        x += {
+            x = 20;
+            2
+        };
+    };
+    // ...not across a closure?
+    let mut y = 0;
+    let b = (y, || y = 1);
+
+    // && and || evaluate left-to-right.
+    let a = {
+        x = 1;
+        true
+    } && (x == 3);
+    let a = {
+        x = 1;
+        true
+    } || (x == 3);
+
+    // Make sure we don't get confused by alpha conversion.
+    let a = {
+        let mut x = 1;
+        x = 2;
+        1
+    } + x;
+
+    // No warning if we don't read the variable...
+    x = {
+        x = 20;
+        2
+    };
+    // ...if the assignment is in a closure...
+    let b = {
+        || {
+            x = 1;
+        };
+        1
+    } + x;
+    // ... or the access is under an address.
+    let b = (
+        {
+            let p = &x;
+            1
+        },
+        {
+            x = 1;
+            x
+        },
+    );
+
+    // Limitation: l-values other than simple variables don't trigger
+    // the warning.
+    let mut tup = (0, 0);
+    let c = {
+        tup.0 = 1;
+        1
+    } + tup.0;
+    // Limitation: you can get away with a read under address-of.
+    let mut z = 0;
+    let b = (
+        &{
+            z = x;
+            x
+        },
+        {
+            x = 3;
+            x
+        },
+    );
+}
diff --git a/src/tools/clippy/tests/ui/eval_order_dependence.stderr b/src/tools/clippy/tests/ui/eval_order_dependence.stderr
new file mode 100644
index 00000000000..8f4fa2228f7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eval_order_dependence.stderr
@@ -0,0 +1,51 @@
+error: unsequenced read of a variable
+  --> $DIR/eval_order_dependence.rs:15:9
+   |
+LL |     } + x;
+   |         ^
+   |
+   = note: `-D clippy::eval-order-dependence` implied by `-D warnings`
+note: whether read occurs before this write depends on evaluation order
+  --> $DIR/eval_order_dependence.rs:13:9
+   |
+LL |         x = 1;
+   |         ^^^^^
+
+error: unsequenced read of a variable
+  --> $DIR/eval_order_dependence.rs:18:5
+   |
+LL |     x += {
+   |     ^
+   |
+note: whether read occurs before this write depends on evaluation order
+  --> $DIR/eval_order_dependence.rs:19:9
+   |
+LL |         x = 20;
+   |         ^^^^^^
+
+error: unsequenced read of a variable
+  --> $DIR/eval_order_dependence.rs:31:12
+   |
+LL |         a: x,
+   |            ^
+   |
+note: whether read occurs before this write depends on evaluation order
+  --> $DIR/eval_order_dependence.rs:33:13
+   |
+LL |             x = 6;
+   |             ^^^^^
+
+error: unsequenced read of a variable
+  --> $DIR/eval_order_dependence.rs:40:9
+   |
+LL |         x += {
+   |         ^
+   |
+note: whether read occurs before this write depends on evaluation order
+  --> $DIR/eval_order_dependence.rs:41:13
+   |
+LL |             x = 20;
+   |             ^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed
new file mode 100644
index 00000000000..bf0325fec79
--- /dev/null
+++ b/src/tools/clippy/tests/ui/excessive_precision.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::excessive_precision)]
+#![allow(dead_code, unused_variables, clippy::print_literal)]
+
+fn main() {
+    // Consts
+    const GOOD32: f32 = 0.123_456;
+    const GOOD32_SM: f32 = 0.000_000_000_1;
+    const GOOD32_DOT: f32 = 10_000_000_000.0;
+    const GOOD32_EDGE: f32 = 1.000_000_8;
+    const GOOD64: f64 = 0.123_456_789_012;
+    const GOOD64_SM: f32 = 0.000_000_000_000_000_1;
+    const GOOD64_DOT: f32 = 10_000_000_000_000_000.0;
+
+    const BAD32_1: f32 = 0.123_456_79_f32;
+    const BAD32_2: f32 = 0.123_456_79;
+    const BAD32_3: f32 = 0.1;
+    const BAD32_EDGE: f32 = 1.000_001;
+
+    const BAD64_1: f64 = 0.123_456_789_012_345_66_f64;
+    const BAD64_2: f64 = 0.123_456_789_012_345_66;
+    const BAD64_3: f64 = 0.1;
+
+    // Literal as param
+    println!("{:?}", 8.888_888_888_888_89);
+
+    // // TODO add inferred type tests for f32
+    // Locals
+    let good32: f32 = 0.123_456_f32;
+    let good32_2: f32 = 0.123_456;
+
+    let good64: f64 = 0.123_456_789_012;
+    let good64_suf: f64 = 0.123_456_789_012f64;
+    let good64_inf = 0.123_456_789_012;
+
+    let bad32: f32 = 1.123_456_8;
+    let bad32_suf: f32 = 1.123_456_8_f32;
+    let bad32_inf = 1.123_456_8_f32;
+
+    let bad64: f64 = 0.123_456_789_012_345_66;
+    let bad64_suf: f64 = 0.123_456_789_012_345_66_f64;
+    let bad64_inf = 0.123_456_789_012_345_66;
+
+    // Vectors
+    let good_vec32: Vec<f32> = vec![0.123_456];
+    let good_vec64: Vec<f64> = vec![0.123_456_789];
+
+    let bad_vec32: Vec<f32> = vec![0.123_456_79];
+    let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
+
+    // Exponential float notation
+    let good_e32: f32 = 1e-10;
+    let bad_e32: f32 = 1.123_456_8e-10;
+
+    let good_bige32: f32 = 1E-10;
+    let bad_bige32: f32 = 1.123_456_8E-10;
+
+    // Inferred type
+    let good_inferred: f32 = 1f32 * 1_000_000_000.;
+
+    // issue #2840
+    let num = 0.000_000_000_01e-10f64;
+}
diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs
new file mode 100644
index 00000000000..ce4722a90f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/excessive_precision.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::excessive_precision)]
+#![allow(dead_code, unused_variables, clippy::print_literal)]
+
+fn main() {
+    // Consts
+    const GOOD32: f32 = 0.123_456;
+    const GOOD32_SM: f32 = 0.000_000_000_1;
+    const GOOD32_DOT: f32 = 10_000_000_000.0;
+    const GOOD32_EDGE: f32 = 1.000_000_8;
+    const GOOD64: f64 = 0.123_456_789_012;
+    const GOOD64_SM: f32 = 0.000_000_000_000_000_1;
+    const GOOD64_DOT: f32 = 10_000_000_000_000_000.0;
+
+    const BAD32_1: f32 = 0.123_456_789_f32;
+    const BAD32_2: f32 = 0.123_456_789;
+    const BAD32_3: f32 = 0.100_000_000_000_1;
+    const BAD32_EDGE: f32 = 1.000_000_9;
+
+    const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
+    const BAD64_2: f64 = 0.123_456_789_012_345_67;
+    const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
+
+    // Literal as param
+    println!("{:?}", 8.888_888_888_888_888_888_888);
+
+    // // TODO add inferred type tests for f32
+    // Locals
+    let good32: f32 = 0.123_456_f32;
+    let good32_2: f32 = 0.123_456;
+
+    let good64: f64 = 0.123_456_789_012;
+    let good64_suf: f64 = 0.123_456_789_012f64;
+    let good64_inf = 0.123_456_789_012;
+
+    let bad32: f32 = 1.123_456_789;
+    let bad32_suf: f32 = 1.123_456_789_f32;
+    let bad32_inf = 1.123_456_789_f32;
+
+    let bad64: f64 = 0.123_456_789_012_345_67;
+    let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
+    let bad64_inf = 0.123_456_789_012_345_67;
+
+    // Vectors
+    let good_vec32: Vec<f32> = vec![0.123_456];
+    let good_vec64: Vec<f64> = vec![0.123_456_789];
+
+    let bad_vec32: Vec<f32> = vec![0.123_456_789];
+    let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
+
+    // Exponential float notation
+    let good_e32: f32 = 1e-10;
+    let bad_e32: f32 = 1.123_456_788_888e-10;
+
+    let good_bige32: f32 = 1E-10;
+    let bad_bige32: f32 = 1.123_456_788_888E-10;
+
+    // Inferred type
+    let good_inferred: f32 = 1f32 * 1_000_000_000.;
+
+    // issue #2840
+    let num = 0.000_000_000_01e-10f64;
+}
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
new file mode 100644
index 00000000000..599773f2f70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -0,0 +1,112 @@
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:15:26
+   |
+LL |     const BAD32_1: f32 = 0.123_456_789_f32;
+   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32`
+   |
+   = note: `-D clippy::excessive-precision` implied by `-D warnings`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:16:26
+   |
+LL |     const BAD32_2: f32 = 0.123_456_789;
+   |                          ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:17:26
+   |
+LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
+   |                          ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:18:29
+   |
+LL |     const BAD32_EDGE: f32 = 1.000_000_9;
+   |                             ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:20:26
+   |
+LL |     const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:21:26
+   |
+LL |     const BAD64_2: f64 = 0.123_456_789_012_345_67;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:22:26
+   |
+LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:25:22
+   |
+LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:36:22
+   |
+LL |     let bad32: f32 = 1.123_456_789;
+   |                      ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:37:26
+   |
+LL |     let bad32_suf: f32 = 1.123_456_789_f32;
+   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:38:21
+   |
+LL |     let bad32_inf = 1.123_456_789_f32;
+   |                     ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:40:22
+   |
+LL |     let bad64: f64 = 0.123_456_789_012_345_67;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:41:26
+   |
+LL |     let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:42:21
+   |
+LL |     let bad64_inf = 0.123_456_789_012_345_67;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:48:36
+   |
+LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
+   |                                    ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:49:36
+   |
+LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:53:24
+   |
+LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
+   |                        ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10`
+
+error: float has excessive precision
+  --> $DIR/excessive_precision.rs:56:27
+   |
+LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
+   |                           ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/exit1.rs b/src/tools/clippy/tests/ui/exit1.rs
new file mode 100644
index 00000000000..4eac6eb7467
--- /dev/null
+++ b/src/tools/clippy/tests/ui/exit1.rs
@@ -0,0 +1,15 @@
+#[warn(clippy::exit)]
+
+fn not_main() {
+    if true {
+        std::process::exit(4);
+    }
+}
+
+fn main() {
+    if true {
+        std::process::exit(2);
+    };
+    not_main();
+    std::process::exit(1);
+}
diff --git a/src/tools/clippy/tests/ui/exit1.stderr b/src/tools/clippy/tests/ui/exit1.stderr
new file mode 100644
index 00000000000..a8d3956aa27
--- /dev/null
+++ b/src/tools/clippy/tests/ui/exit1.stderr
@@ -0,0 +1,10 @@
+error: usage of `process::exit`
+  --> $DIR/exit1.rs:5:9
+   |
+LL |         std::process::exit(4);
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::exit` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/exit2.rs b/src/tools/clippy/tests/ui/exit2.rs
new file mode 100644
index 00000000000..4b693ed7083
--- /dev/null
+++ b/src/tools/clippy/tests/ui/exit2.rs
@@ -0,0 +1,13 @@
+#[warn(clippy::exit)]
+
+fn also_not_main() {
+    std::process::exit(3);
+}
+
+fn main() {
+    if true {
+        std::process::exit(2);
+    };
+    also_not_main();
+    std::process::exit(1);
+}
diff --git a/src/tools/clippy/tests/ui/exit2.stderr b/src/tools/clippy/tests/ui/exit2.stderr
new file mode 100644
index 00000000000..7263e156a9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/exit2.stderr
@@ -0,0 +1,10 @@
+error: usage of `process::exit`
+  --> $DIR/exit2.rs:4:5
+   |
+LL |     std::process::exit(3);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::exit` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/exit3.rs b/src/tools/clippy/tests/ui/exit3.rs
new file mode 100644
index 00000000000..9dc0e1015a4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/exit3.rs
@@ -0,0 +1,8 @@
+#[warn(clippy::exit)]
+
+fn main() {
+    if true {
+        std::process::exit(2);
+    };
+    std::process::exit(1);
+}
diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs
new file mode 100644
index 00000000000..0bd4252c49a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/expect.rs
@@ -0,0 +1,16 @@
+#![warn(clippy::option_expect_used, clippy::result_expect_used)]
+
+fn expect_option() {
+    let opt = Some(0);
+    let _ = opt.expect("");
+}
+
+fn expect_result() {
+    let res: Result<u8, ()> = Ok(0);
+    let _ = res.expect("");
+}
+
+fn main() {
+    expect_option();
+    expect_result();
+}
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
new file mode 100644
index 00000000000..adf9f4f1921
--- /dev/null
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -0,0 +1,20 @@
+error: used `expect()` on `an Option` value
+  --> $DIR/expect.rs:5:13
+   |
+LL |     let _ = opt.expect("");
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-expect-used` implied by `-D warnings`
+   = help: if this value is an `None`, it will panic
+
+error: used `expect()` on `a Result` value
+  --> $DIR/expect.rs:10:13
+   |
+LL |     let _ = res.expect("");
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::result-expect-used` implied by `-D warnings`
+   = help: if this value is an `Err`, it will panic
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed
new file mode 100644
index 00000000000..f3d8a941a92
--- /dev/null
+++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed
@@ -0,0 +1,94 @@
+// run-rustfix
+
+#![warn(clippy::expect_fun_call)]
+
+/// Checks implementation of the `EXPECT_FUN_CALL` lint
+
+fn main() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Self {
+            Foo
+        }
+
+        fn expect(&self, msg: &str) {
+            panic!("{}", msg)
+        }
+    }
+
+    let with_some = Some("value");
+    with_some.expect("error");
+
+    let with_none: Option<i32> = None;
+    with_none.expect("error");
+
+    let error_code = 123_i32;
+    let with_none_and_format: Option<i32> = None;
+    with_none_and_format.unwrap_or_else(|| panic!("Error {}: fake error", error_code));
+
+    let with_none_and_as_str: Option<i32> = None;
+    with_none_and_as_str.unwrap_or_else(|| panic!("Error {}: fake error", error_code));
+
+    let with_ok: Result<(), ()> = Ok(());
+    with_ok.expect("error");
+
+    let with_err: Result<(), ()> = Err(());
+    with_err.expect("error");
+
+    let error_code = 123_i32;
+    let with_err_and_format: Result<(), ()> = Err(());
+    with_err_and_format.unwrap_or_else(|_| panic!("Error {}: fake error", error_code));
+
+    let with_err_and_as_str: Result<(), ()> = Err(());
+    with_err_and_as_str.unwrap_or_else(|_| panic!("Error {}: fake error", error_code));
+
+    let with_dummy_type = Foo::new();
+    with_dummy_type.expect("another test string");
+
+    let with_dummy_type_and_format = Foo::new();
+    with_dummy_type_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_dummy_type_and_as_str = Foo::new();
+    with_dummy_type_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    //Issue #2937
+    Some("foo").unwrap_or_else(|| panic!("{} {}", 1, 2));
+
+    //Issue #2979 - this should not lint
+    {
+        let msg = "bar";
+        Some("foo").expect(msg);
+    }
+
+    {
+        fn get_string() -> String {
+            "foo".to_string()
+        }
+
+        fn get_static_str() -> &'static str {
+            "foo"
+        }
+
+        fn get_non_static_str(_: &u32) -> &str {
+            "foo"
+        }
+
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+
+        Some("foo").unwrap_or_else(|| { panic!(get_static_str()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) });
+    }
+
+    //Issue #3839
+    Some(true).unwrap_or_else(|| panic!("key {}, {}", 1, 2));
+
+    //Issue #4912 - the receiver is a &Option
+    {
+        let opt = Some(1);
+        let opt_ref = &opt;
+        opt_ref.unwrap_or_else(|| panic!("{:?}", opt_ref));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs
new file mode 100644
index 00000000000..60bbaa89d42
--- /dev/null
+++ b/src/tools/clippy/tests/ui/expect_fun_call.rs
@@ -0,0 +1,94 @@
+// run-rustfix
+
+#![warn(clippy::expect_fun_call)]
+
+/// Checks implementation of the `EXPECT_FUN_CALL` lint
+
+fn main() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Self {
+            Foo
+        }
+
+        fn expect(&self, msg: &str) {
+            panic!("{}", msg)
+        }
+    }
+
+    let with_some = Some("value");
+    with_some.expect("error");
+
+    let with_none: Option<i32> = None;
+    with_none.expect("error");
+
+    let error_code = 123_i32;
+    let with_none_and_format: Option<i32> = None;
+    with_none_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_none_and_as_str: Option<i32> = None;
+    with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    let with_ok: Result<(), ()> = Ok(());
+    with_ok.expect("error");
+
+    let with_err: Result<(), ()> = Err(());
+    with_err.expect("error");
+
+    let error_code = 123_i32;
+    let with_err_and_format: Result<(), ()> = Err(());
+    with_err_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_err_and_as_str: Result<(), ()> = Err(());
+    with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    let with_dummy_type = Foo::new();
+    with_dummy_type.expect("another test string");
+
+    let with_dummy_type_and_format = Foo::new();
+    with_dummy_type_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_dummy_type_and_as_str = Foo::new();
+    with_dummy_type_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    //Issue #2937
+    Some("foo").expect(format!("{} {}", 1, 2).as_ref());
+
+    //Issue #2979 - this should not lint
+    {
+        let msg = "bar";
+        Some("foo").expect(msg);
+    }
+
+    {
+        fn get_string() -> String {
+            "foo".to_string()
+        }
+
+        fn get_static_str() -> &'static str {
+            "foo"
+        }
+
+        fn get_non_static_str(_: &u32) -> &str {
+            "foo"
+        }
+
+        Some("foo").expect(&get_string());
+        Some("foo").expect(get_string().as_ref());
+        Some("foo").expect(get_string().as_str());
+
+        Some("foo").expect(get_static_str());
+        Some("foo").expect(get_non_static_str(&0));
+    }
+
+    //Issue #3839
+    Some(true).expect(&format!("key {}, {}", 1, 2));
+
+    //Issue #4912 - the receiver is a &Option
+    {
+        let opt = Some(1);
+        let opt_ref = &opt;
+        opt_ref.expect(&format!("{:?}", opt_ref));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr
new file mode 100644
index 00000000000..a492e2df89d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr
@@ -0,0 +1,76 @@
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:28:26
+   |
+LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+   |
+   = note: `-D clippy::expect-fun-call` implied by `-D warnings`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:31:26
+   |
+LL |     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:41:25
+   |
+LL |     with_err_and_format.expect(&format!("Error {}: fake error", error_code));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:44:25
+   |
+LL |     with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:56:17
+   |
+LL |     Some("foo").expect(format!("{} {}", 1, 2).as_ref());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:77:21
+   |
+LL |         Some("foo").expect(&get_string());
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:78:21
+   |
+LL |         Some("foo").expect(get_string().as_ref());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:79:21
+   |
+LL |         Some("foo").expect(get_string().as_str());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:81:21
+   |
+LL |         Some("foo").expect(get_static_str());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:82:21
+   |
+LL |         Some("foo").expect(get_non_static_str(&0));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:86:16
+   |
+LL |     Some(true).expect(&format!("key {}, {}", 1, 2));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:92:17
+   |
+LL |         opt_ref.expect(&format!("{:?}", opt_ref));
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
new file mode 100644
index 00000000000..aa6ef162fe4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -0,0 +1,147 @@
+#![warn(clippy::explicit_counter_loop)]
+
+fn main() {
+    let mut vec = vec![1, 2, 3, 4];
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 1;
+    _index = 0;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &mut vec {
+        _index += 1;
+    }
+
+    let mut _index = 0;
+    for _v in vec {
+        _index += 1;
+    }
+}
+
+mod issue_1219 {
+    pub fn test() {
+        // should not trigger the lint because variable is used after the loop #473
+        let vec = vec![1, 2, 3];
+        let mut index = 0;
+        for _v in &vec {
+            index += 1
+        }
+        println!("index: {}", index);
+
+        // should not trigger the lint because the count is conditional #1219
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            if ch == 'a' {
+                continue;
+            }
+            count += 1;
+            println!("{}", count);
+        }
+
+        // should not trigger the lint because the count is conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            if ch == 'a' {
+                count += 1;
+            }
+            println!("{}", count);
+        }
+
+        // should trigger the lint because the count is not conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            if ch == 'a' {
+                continue;
+            }
+            println!("{}", count);
+        }
+
+        // should trigger the lint because the count is not conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            for i in 0..2 {
+                let _ = 123;
+            }
+            println!("{}", count);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            for i in 0..2 {
+                count += 1;
+            }
+            println!("{}", count);
+        }
+    }
+}
+
+mod issue_3308 {
+    pub fn test() {
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        let erasures = vec![];
+        for i in 0..10 {
+            while erasures.contains(&(i + skips)) {
+                skips += 1;
+            }
+            println!("{}", skips);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        for i in 0..10 {
+            let mut j = 0;
+            while j < 5 {
+                skips += 1;
+                j += 1;
+            }
+            println!("{}", skips);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        for i in 0..10 {
+            for j in 0..5 {
+                skips += 1;
+            }
+            println!("{}", skips);
+        }
+    }
+}
+
+mod issue_1670 {
+    pub fn test() {
+        let mut count = 0;
+        for _i in 3..10 {
+            count += 1;
+        }
+    }
+}
+
+mod issue_4732 {
+    pub fn test() {
+        let slice = &[1, 2, 3];
+        let mut index = 0;
+
+        // should not trigger the lint because the count is used after the loop
+        for _v in slice {
+            index += 1
+        }
+        let _closure = || println!("index: {}", index);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
new file mode 100644
index 00000000000..931af46efe6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
@@ -0,0 +1,46 @@
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:6:5
+   |
+LL |     for _v in &vec {
+   |     ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()`
+   |
+   = note: `-D clippy::explicit-counter-loop` implied by `-D warnings`
+
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:12:5
+   |
+LL |     for _v in &vec {
+   |     ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()`
+
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:17:5
+   |
+LL |     for _v in &mut vec {
+   |     ^^^^^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter_mut().enumerate()`
+
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:22:5
+   |
+LL |     for _v in vec {
+   |     ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:61:9
+   |
+LL |         for ch in text.chars() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:72:9
+   |
+LL |         for ch in text.chars() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:130:9
+   |
+LL |         for _i in 3..10 {
+   |         ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/explicit_write.fixed b/src/tools/clippy/tests/ui/explicit_write.fixed
new file mode 100644
index 00000000000..692d2ca675f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write.fixed
@@ -0,0 +1,51 @@
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::explicit_write)]
+
+fn stdout() -> String {
+    String::new()
+}
+
+fn stderr() -> String {
+    String::new()
+}
+
+fn main() {
+    // these should warn
+    {
+        use std::io::Write;
+        print!("test");
+        eprint!("test");
+        println!("test");
+        eprintln!("test");
+        print!("test");
+        eprint!("test");
+
+        // including newlines
+        println!("test\ntest");
+        eprintln!("test\ntest");
+    }
+    // these should not warn, different destination
+    {
+        use std::fmt::Write;
+        let mut s = String::new();
+        write!(s, "test").unwrap();
+        write!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        write!(stdout(), "test").unwrap();
+        write!(stderr(), "test").unwrap();
+        writeln!(stdout(), "test").unwrap();
+        writeln!(stderr(), "test").unwrap();
+        stdout().write_fmt(format_args!("test")).unwrap();
+        stderr().write_fmt(format_args!("test")).unwrap();
+    }
+    // these should not warn, no unwrap
+    {
+        use std::io::Write;
+        std::io::stdout().write_fmt(format_args!("test")).expect("no stdout");
+        std::io::stderr().write_fmt(format_args!("test")).expect("no stderr");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_write.rs b/src/tools/clippy/tests/ui/explicit_write.rs
new file mode 100644
index 00000000000..455c5ef55d0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write.rs
@@ -0,0 +1,51 @@
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::explicit_write)]
+
+fn stdout() -> String {
+    String::new()
+}
+
+fn stderr() -> String {
+    String::new()
+}
+
+fn main() {
+    // these should warn
+    {
+        use std::io::Write;
+        write!(std::io::stdout(), "test").unwrap();
+        write!(std::io::stderr(), "test").unwrap();
+        writeln!(std::io::stdout(), "test").unwrap();
+        writeln!(std::io::stderr(), "test").unwrap();
+        std::io::stdout().write_fmt(format_args!("test")).unwrap();
+        std::io::stderr().write_fmt(format_args!("test")).unwrap();
+
+        // including newlines
+        writeln!(std::io::stdout(), "test\ntest").unwrap();
+        writeln!(std::io::stderr(), "test\ntest").unwrap();
+    }
+    // these should not warn, different destination
+    {
+        use std::fmt::Write;
+        let mut s = String::new();
+        write!(s, "test").unwrap();
+        write!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        write!(stdout(), "test").unwrap();
+        write!(stderr(), "test").unwrap();
+        writeln!(stdout(), "test").unwrap();
+        writeln!(stderr(), "test").unwrap();
+        stdout().write_fmt(format_args!("test")).unwrap();
+        stderr().write_fmt(format_args!("test")).unwrap();
+    }
+    // these should not warn, no unwrap
+    {
+        use std::io::Write;
+        std::io::stdout().write_fmt(format_args!("test")).expect("no stdout");
+        std::io::stderr().write_fmt(format_args!("test")).expect("no stderr");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_write.stderr b/src/tools/clippy/tests/ui/explicit_write.stderr
new file mode 100644
index 00000000000..9feef9c0dc8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write.stderr
@@ -0,0 +1,52 @@
+error: use of `write!(stdout(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:17:9
+   |
+LL |         write!(std::io::stdout(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+   |
+   = note: `-D clippy::explicit-write` implied by `-D warnings`
+
+error: use of `write!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:18:9
+   |
+LL |         write!(std::io::stderr(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
+
+error: use of `writeln!(stdout(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:19:9
+   |
+LL |         writeln!(std::io::stdout(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:20:9
+   |
+LL |         writeln!(std::io::stderr(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")`
+
+error: use of `stdout().write_fmt(...).unwrap()`
+  --> $DIR/explicit_write.rs:21:9
+   |
+LL |         std::io::stdout().write_fmt(format_args!("test")).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+
+error: use of `stderr().write_fmt(...).unwrap()`
+  --> $DIR/explicit_write.rs:22:9
+   |
+LL |         std::io::stderr().write_fmt(format_args!("test")).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
+
+error: use of `writeln!(stdout(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:25:9
+   |
+LL |         writeln!(std::io::stdout(), "test/ntest").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:26:9
+   |
+LL |         writeln!(std::io::stderr(), "test/ntest").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs
new file mode 100644
index 00000000000..f21e8ef935b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs
@@ -0,0 +1,8 @@
+#![allow(unused_imports, clippy::blacklisted_name)]
+#![warn(clippy::explicit_write)]
+
+fn main() {
+    use std::io::Write;
+    let bar = "bar";
+    writeln!(std::io::stderr(), "foo {}", bar).unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr
new file mode 100644
index 00000000000..77cadb99bb5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr
@@ -0,0 +1,10 @@
+error: use of `writeln!(stderr(), ...).unwrap()`. Consider using `eprintln!` instead
+  --> $DIR/explicit_write_non_rustfix.rs:7:5
+   |
+LL |     writeln!(std::io::stderr(), "foo {}", bar).unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::explicit-write` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
new file mode 100644
index 00000000000..ddbf4e98c51
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
@@ -0,0 +1,69 @@
+#![allow(unused, dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value)]
+#![warn(clippy::extra_unused_lifetimes)]
+
+fn empty() {}
+
+fn used_lt<'a>(x: &'a u8) {}
+
+fn unused_lt<'a>(x: u8) {}
+
+fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
+    // 'a is useless here since it's not directly bound
+}
+
+fn lt_return<'a, 'b: 'a>(x: &'b u8) -> &'a u8 {
+    panic!()
+}
+
+fn lt_return_only<'a>() -> &'a u8 {
+    panic!()
+}
+
+fn unused_lt_blergh<'a>(x: Option<Box<dyn Send + 'a>>) {}
+
+trait Foo<'a> {
+    fn x(&self, a: &'a u8);
+}
+
+impl<'a> Foo<'a> for u8 {
+    fn x(&self, a: &'a u8) {}
+}
+
+struct Bar;
+
+impl Bar {
+    fn x<'a>(&self) {}
+}
+
+// test for #489 (used lifetimes in bounds)
+pub fn parse<'a, I: Iterator<Item = &'a str>>(_it: &mut I) {
+    unimplemented!()
+}
+pub fn parse2<'a, I>(_it: &mut I)
+where
+    I: Iterator<Item = &'a str>,
+{
+    unimplemented!()
+}
+
+struct X {
+    x: u32,
+}
+
+impl X {
+    fn self_ref_with_lifetime<'a>(&'a self) {}
+    fn explicit_self_with_lifetime<'a>(self: &'a Self) {}
+}
+
+// Methods implementing traits must have matching lifetimes
+mod issue4291 {
+    trait BadTrait {
+        fn unused_lt<'a>(x: u8) {}
+    }
+
+    impl BadTrait for () {
+        fn unused_lt<'a>(_x: u8) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
new file mode 100644
index 00000000000..16bbb1c037d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
@@ -0,0 +1,28 @@
+error: this lifetime isn't used in the function definition
+  --> $DIR/extra_unused_lifetimes.rs:8:14
+   |
+LL | fn unused_lt<'a>(x: u8) {}
+   |              ^^
+   |
+   = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings`
+
+error: this lifetime isn't used in the function definition
+  --> $DIR/extra_unused_lifetimes.rs:10:25
+   |
+LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
+   |                         ^^
+
+error: this lifetime isn't used in the function definition
+  --> $DIR/extra_unused_lifetimes.rs:35:10
+   |
+LL |     fn x<'a>(&self) {}
+   |          ^^
+
+error: this lifetime isn't used in the function definition
+  --> $DIR/extra_unused_lifetimes.rs:61:22
+   |
+LL |         fn unused_lt<'a>(x: u8) {}
+   |                      ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.rs b/src/tools/clippy/tests/ui/fallible_impl_from.rs
new file mode 100644
index 00000000000..679f4a7dc35
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fallible_impl_from.rs
@@ -0,0 +1,76 @@
+#![deny(clippy::fallible_impl_from)]
+
+// docs example
+struct Foo(i32);
+impl From<String> for Foo {
+    fn from(s: String) -> Self {
+        Foo(s.parse().unwrap())
+    }
+}
+
+struct Valid(Vec<u8>);
+
+impl<'a> From<&'a str> for Valid {
+    fn from(s: &'a str) -> Valid {
+        Valid(s.to_owned().into_bytes())
+    }
+}
+impl From<usize> for Valid {
+    fn from(i: usize) -> Valid {
+        Valid(Vec::with_capacity(i))
+    }
+}
+
+struct Invalid;
+
+impl From<usize> for Invalid {
+    fn from(i: usize) -> Invalid {
+        if i != 42 {
+            panic!();
+        }
+        Invalid
+    }
+}
+
+impl From<Option<String>> for Invalid {
+    fn from(s: Option<String>) -> Invalid {
+        let s = s.unwrap();
+        if !s.is_empty() {
+            panic!(42);
+        } else if s.parse::<u32>().unwrap() != 42 {
+            panic!("{:?}", s);
+        }
+        Invalid
+    }
+}
+
+trait ProjStrTrait {
+    type ProjString;
+}
+impl<T> ProjStrTrait for Box<T> {
+    type ProjString = String;
+}
+impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
+    fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
+        if s.parse::<u32>().ok().unwrap() != 42 {
+            panic!("{:?}", s);
+        }
+        Invalid
+    }
+}
+
+struct Unreachable;
+
+impl From<String> for Unreachable {
+    fn from(s: String) -> Unreachable {
+        if s.is_empty() {
+            return Unreachable;
+        }
+        match s.chars().next() {
+            Some(_) => Unreachable,
+            None => unreachable!(), // do not lint the unreachable macro
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.stderr b/src/tools/clippy/tests/ui/fallible_impl_from.stderr
new file mode 100644
index 00000000000..ab976b947b3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fallible_impl_from.stderr
@@ -0,0 +1,93 @@
+error: consider implementing `TryFrom` instead
+  --> $DIR/fallible_impl_from.rs:5:1
+   |
+LL | / impl From<String> for Foo {
+LL | |     fn from(s: String) -> Self {
+LL | |         Foo(s.parse().unwrap())
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: the lint level is defined here
+  --> $DIR/fallible_impl_from.rs:1:9
+   |
+LL | #![deny(clippy::fallible_impl_from)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
+note: potential failure(s)
+  --> $DIR/fallible_impl_from.rs:7:13
+   |
+LL |         Foo(s.parse().unwrap())
+   |             ^^^^^^^^^^^^^^^^^^
+
+error: consider implementing `TryFrom` instead
+  --> $DIR/fallible_impl_from.rs:26:1
+   |
+LL | / impl From<usize> for Invalid {
+LL | |     fn from(i: usize) -> Invalid {
+LL | |         if i != 42 {
+LL | |             panic!();
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
+note: potential failure(s)
+  --> $DIR/fallible_impl_from.rs:29:13
+   |
+LL |             panic!();
+   |             ^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: consider implementing `TryFrom` instead
+  --> $DIR/fallible_impl_from.rs:35:1
+   |
+LL | / impl From<Option<String>> for Invalid {
+LL | |     fn from(s: Option<String>) -> Invalid {
+LL | |         let s = s.unwrap();
+LL | |         if !s.is_empty() {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
+note: potential failure(s)
+  --> $DIR/fallible_impl_from.rs:37:17
+   |
+LL |         let s = s.unwrap();
+   |                 ^^^^^^^^^^
+LL |         if !s.is_empty() {
+LL |             panic!(42);
+   |             ^^^^^^^^^^^
+LL |         } else if s.parse::<u32>().unwrap() != 42 {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             panic!("{:?}", s);
+   |             ^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: consider implementing `TryFrom` instead
+  --> $DIR/fallible_impl_from.rs:53:1
+   |
+LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
+LL | |     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
+LL | |         if s.parse::<u32>().ok().unwrap() != 42 {
+LL | |             panic!("{:?}", s);
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
+note: potential failure(s)
+  --> $DIR/fallible_impl_from.rs:55:12
+   |
+LL |         if s.parse::<u32>().ok().unwrap() != 42 {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             panic!("{:?}", s);
+   |             ^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filetype_is_file.rs b/src/tools/clippy/tests/ui/filetype_is_file.rs
new file mode 100644
index 00000000000..5de8fe8cdd7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filetype_is_file.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::filetype_is_file)]
+
+fn main() -> std::io::Result<()> {
+    use std::fs;
+    use std::ops::BitOr;
+
+    // !filetype.is_dir()
+    if fs::metadata("foo.txt")?.file_type().is_file() {
+        // read file
+    }
+
+    // positive of filetype.is_dir()
+    if !fs::metadata("foo.txt")?.file_type().is_file() {
+        // handle dir
+    }
+
+    // false positive of filetype.is_dir()
+    if !fs::metadata("foo.txt")?.file_type().is_file().bitor(true) {
+        // ...
+    }
+
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/filetype_is_file.stderr b/src/tools/clippy/tests/ui/filetype_is_file.stderr
new file mode 100644
index 00000000000..cd1e3ac37fe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filetype_is_file.stderr
@@ -0,0 +1,27 @@
+error: `FileType::is_file()` only covers regular files
+  --> $DIR/filetype_is_file.rs:8:8
+   |
+LL |     if fs::metadata("foo.txt")?.file_type().is_file() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filetype-is-file` implied by `-D warnings`
+   = help: use `!FileType::is_dir()` instead
+
+error: `!FileType::is_file()` only denies regular files
+  --> $DIR/filetype_is_file.rs:13:8
+   |
+LL |     if !fs::metadata("foo.txt")?.file_type().is_file() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `FileType::is_dir()` instead
+
+error: `FileType::is_file()` only covers regular files
+  --> $DIR/filetype_is_file.rs:18:9
+   |
+LL |     if !fs::metadata("foo.txt")?.file_type().is_file().bitor(true) {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `!FileType::is_dir()` instead
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filter_map_next.rs b/src/tools/clippy/tests/ui/filter_map_next.rs
new file mode 100644
index 00000000000..f5d051be198
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_next.rs
@@ -0,0 +1,20 @@
+#![warn(clippy::all, clippy::pedantic)]
+
+fn main() {
+    let a = ["1", "lol", "3", "NaN", "5"];
+
+    let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+    assert_eq!(element, Some(1));
+
+    #[rustfmt::skip]
+    let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
+        .into_iter()
+        .filter_map(|x| {
+            if x == 2 {
+                Some(x * 2)
+            } else {
+                None
+            }
+        })
+        .next();
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next.stderr b/src/tools/clippy/tests/ui/filter_map_next.stderr
new file mode 100644
index 00000000000..d69ae212414
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_next.stderr
@@ -0,0 +1,24 @@
+error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead.
+  --> $DIR/filter_map_next.rs:6:32
+   |
+LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filter-map-next` implied by `-D warnings`
+   = note: replace `filter_map(|s| s.parse().ok()).next()` with `find_map(|s| s.parse().ok())`
+
+error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead.
+  --> $DIR/filter_map_next.rs:10:26
+   |
+LL |       let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
+   |  __________________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| {
+LL | |             if x == 2 {
+...  |
+LL | |         })
+LL | |         .next();
+   | |_______________^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filter_methods.rs b/src/tools/clippy/tests/ui/filter_methods.rs
new file mode 100644
index 00000000000..ef434245fd7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_methods.rs
@@ -0,0 +1,24 @@
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::missing_docs_in_private_items)]
+
+fn main() {
+    let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
+
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter(|&x| x == 0)
+        .flat_map(|x| x.checked_mul(2))
+        .collect();
+
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter_map(|x| x.checked_mul(2))
+        .flat_map(|x| x.checked_mul(2))
+        .collect();
+
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter_map(|x| x.checked_mul(2))
+        .map(|x| x.checked_mul(2))
+        .collect();
+}
diff --git a/src/tools/clippy/tests/ui/filter_methods.stderr b/src/tools/clippy/tests/ui/filter_methods.stderr
new file mode 100644
index 00000000000..84a957a374c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_methods.stderr
@@ -0,0 +1,47 @@
+error: called `filter(p).map(q)` on an `Iterator`
+  --> $DIR/filter_methods.rs:5:21
+   |
+LL |     let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filter-map` implied by `-D warnings`
+   = help: this is more succinctly expressed by calling `.filter_map(..)` instead
+
+error: called `filter(p).flat_map(q)` on an `Iterator`
+  --> $DIR/filter_methods.rs:7:21
+   |
+LL |       let _: Vec<_> = vec![5_i8; 6]
+   |  _____________________^
+LL | |         .into_iter()
+LL | |         .filter(|&x| x == 0)
+LL | |         .flat_map(|x| x.checked_mul(2))
+   | |_______________________________________^
+   |
+   = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
+
+error: called `filter_map(p).flat_map(q)` on an `Iterator`
+  --> $DIR/filter_methods.rs:13:21
+   |
+LL |       let _: Vec<_> = vec![5_i8; 6]
+   |  _____________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| x.checked_mul(2))
+LL | |         .flat_map(|x| x.checked_mul(2))
+   | |_______________________________________^
+   |
+   = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
+
+error: called `filter_map(p).map(q)` on an `Iterator`
+  --> $DIR/filter_methods.rs:19:21
+   |
+LL |       let _: Vec<_> = vec![5_i8; 6]
+   |  _____________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| x.checked_mul(2))
+LL | |         .map(|x| x.checked_mul(2))
+   | |__________________________________^
+   |
+   = help: this is more succinctly expressed by only calling `.filter_map(..)` instead
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/find_map.rs b/src/tools/clippy/tests/ui/find_map.rs
new file mode 100644
index 00000000000..c28cca144ca
--- /dev/null
+++ b/src/tools/clippy/tests/ui/find_map.rs
@@ -0,0 +1,32 @@
+#![warn(clippy::all, clippy::pedantic)]
+
+#[derive(Debug, Copy, Clone)]
+enum Flavor {
+    Chocolate,
+}
+
+#[derive(Debug, Copy, Clone)]
+enum Dessert {
+    Banana,
+    Pudding,
+    Cake(Flavor),
+}
+
+fn main() {
+    let desserts_of_the_week = vec![Dessert::Banana, Dessert::Cake(Flavor::Chocolate), Dessert::Pudding];
+
+    let a = ["lol", "NaN", "2", "5", "Xunda"];
+
+    let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
+
+    let _: Option<Flavor> = desserts_of_the_week
+        .iter()
+        .find(|dessert| match *dessert {
+            Dessert::Cake(_) => true,
+            _ => false,
+        })
+        .map(|dessert| match *dessert {
+            Dessert::Cake(ref flavor) => *flavor,
+            _ => unreachable!(),
+        });
+}
diff --git a/src/tools/clippy/tests/ui/find_map.stderr b/src/tools/clippy/tests/ui/find_map.stderr
new file mode 100644
index 00000000000..92f40fe6f1f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/find_map.stderr
@@ -0,0 +1,26 @@
+error: called `find(p).map(q)` on an `Iterator`
+  --> $DIR/find_map.rs:20:26
+   |
+LL |     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::find-map` implied by `-D warnings`
+   = help: this is more succinctly expressed by calling `.find_map(..)` instead
+
+error: called `find(p).map(q)` on an `Iterator`
+  --> $DIR/find_map.rs:22:29
+   |
+LL |       let _: Option<Flavor> = desserts_of_the_week
+   |  _____________________________^
+LL | |         .iter()
+LL | |         .find(|dessert| match *dessert {
+LL | |             Dessert::Cake(_) => true,
+...  |
+LL | |             _ => unreachable!(),
+LL | |         });
+   | |__________^
+   |
+   = help: this is more succinctly expressed by calling `.find_map(..)` instead
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/float_arithmetic.rs b/src/tools/clippy/tests/ui/float_arithmetic.rs
new file mode 100644
index 00000000000..60fa7569eb9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_arithmetic.rs
@@ -0,0 +1,52 @@
+#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::op_ref
+)]
+
+#[rustfmt::skip]
+fn main() {
+    let mut f = 1.0f32;
+
+    f * 2.0;
+
+    1.0 + f;
+    f * 2.0;
+    f / 2.0;
+    f - 2.0 * 4.2;
+    -f;
+
+    f += 1.0;
+    f -= 1.0;
+    f *= 2.0;
+    f /= 2.0;
+}
+
+// also warn about floating point arith with references involved
+
+pub fn float_arith_ref() {
+    3.1_f32 + &1.2_f32;
+    &3.4_f32 + 1.5_f32;
+    &3.5_f32 + &1.3_f32;
+}
+
+pub fn float_foo(f: &f32) -> f32 {
+    let a = 5.1;
+    a + f
+}
+
+pub fn float_bar(f1: &f32, f2: &f32) -> f32 {
+    f1 + f2
+}
+
+pub fn float_baz(f1: f32, f2: &f32) -> f32 {
+    f1 + f2
+}
+
+pub fn float_qux(f1: f32, f2: f32) -> f32 {
+    (&f1 + &f2)
+}
diff --git a/src/tools/clippy/tests/ui/float_arithmetic.stderr b/src/tools/clippy/tests/ui/float_arithmetic.stderr
new file mode 100644
index 00000000000..1ceffb35bee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_arithmetic.stderr
@@ -0,0 +1,106 @@
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:15:5
+   |
+LL |     f * 2.0;
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::float-arithmetic` implied by `-D warnings`
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:17:5
+   |
+LL |     1.0 + f;
+   |     ^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:18:5
+   |
+LL |     f * 2.0;
+   |     ^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:19:5
+   |
+LL |     f / 2.0;
+   |     ^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:20:5
+   |
+LL |     f - 2.0 * 4.2;
+   |     ^^^^^^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:21:5
+   |
+LL |     -f;
+   |     ^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:23:5
+   |
+LL |     f += 1.0;
+   |     ^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:24:5
+   |
+LL |     f -= 1.0;
+   |     ^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:25:5
+   |
+LL |     f *= 2.0;
+   |     ^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:26:5
+   |
+LL |     f /= 2.0;
+   |     ^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:32:5
+   |
+LL |     3.1_f32 + &1.2_f32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:33:5
+   |
+LL |     &3.4_f32 + 1.5_f32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:34:5
+   |
+LL |     &3.5_f32 + &1.3_f32;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:39:5
+   |
+LL |     a + f
+   |     ^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:43:5
+   |
+LL |     f1 + f2
+   |     ^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:47:5
+   |
+LL |     f1 + f2
+   |     ^^^^^^^
+
+error: floating-point arithmetic detected
+  --> $DIR/float_arithmetic.rs:51:5
+   |
+LL |     (&f1 + &f2)
+   |     ^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
new file mode 100644
index 00000000000..9fa0e5f5c07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -0,0 +1,119 @@
+#![warn(clippy::float_cmp)]
+#![allow(
+    unused,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::cast_lossless,
+    clippy::many_single_char_names
+)]
+
+use std::ops::Add;
+
+const ZERO: f32 = 0.0;
+const ONE: f32 = ZERO + 1.0;
+
+fn twice<T>(x: T) -> T
+where
+    T: Add<T, Output = T> + Copy,
+{
+    x + x
+}
+
+fn eq_fl(x: f32, y: f32) -> bool {
+    if x.is_nan() {
+        y.is_nan()
+    } else {
+        x == y
+    } // no error, inside "eq" fn
+}
+
+fn fl_eq(x: f32, y: f32) -> bool {
+    if x.is_nan() {
+        y.is_nan()
+    } else {
+        x == y
+    } // no error, inside "eq" fn
+}
+
+struct X {
+    val: f32,
+}
+
+impl PartialEq for X {
+    fn eq(&self, o: &X) -> bool {
+        if self.val.is_nan() {
+            o.val.is_nan()
+        } else {
+            self.val == o.val // no error, inside "eq" fn
+        }
+    }
+}
+
+fn main() {
+    ZERO == 0f32; //no error, comparison with zero is ok
+    1.0f32 != f32::INFINITY; // also comparison with infinity
+    1.0f32 != f32::NEG_INFINITY; // and negative infinity
+    ZERO == 0.0; //no error, comparison with zero is ok
+    ZERO + ZERO != 1.0; //no error, comparison with zero is ok
+
+    ONE == 1f32;
+    ONE == 1.0 + 0.0;
+    ONE + ONE == ZERO + ONE + ONE;
+    ONE != 2.0;
+    ONE != 0.0; // no error, comparison with zero is ok
+    twice(ONE) != ONE;
+    ONE as f64 != 2.0;
+    ONE as f64 != 0.0; // no error, comparison with zero is ok
+
+    let x: f64 = 1.0;
+
+    x == 1.0;
+    x != 0f64; // no error, comparison with zero is ok
+
+    twice(x) != twice(ONE as f64);
+
+    x < 0.0; // no errors, lower or greater comparisons need no fuzzyness
+    x > 0.0;
+    x <= 0.0;
+    x >= 0.0;
+
+    let xs: [f32; 1] = [0.0];
+    let a: *const f32 = xs.as_ptr();
+    let b: *const f32 = xs.as_ptr();
+
+    assert_eq!(a, b); // no errors
+
+    const ZERO_ARRAY: [f32; 2] = [0.0, 0.0];
+    const NON_ZERO_ARRAY: [f32; 2] = [0.0, 0.1];
+
+    let i = 0;
+    let j = 1;
+
+    ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i
+    NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
+
+    let a1: [f32; 1] = [0.0];
+    let a2: [f32; 1] = [1.1];
+
+    a1 == a2;
+    a1[0] == a2[0];
+
+    // no errors - comparing signums is ok
+    let x32 = 3.21f32;
+    1.23f32.signum() == x32.signum();
+    1.23f32.signum() == -(x32.signum());
+    1.23f32.signum() == 3.21f32.signum();
+
+    1.23f32.signum() != x32.signum();
+    1.23f32.signum() != -(x32.signum());
+    1.23f32.signum() != 3.21f32.signum();
+
+    let x64 = 3.21f64;
+    1.23f64.signum() == x64.signum();
+    1.23f64.signum() == -(x64.signum());
+    1.23f64.signum() == 3.21f64.signum();
+
+    1.23f64.signum() != x64.signum();
+    1.23f64.signum() != -(x64.signum());
+    1.23f64.signum() != 3.21f64.signum();
+}
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
new file mode 100644
index 00000000000..2d454e8e70d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -0,0 +1,51 @@
+error: strict comparison of `f32` or `f64`
+  --> $DIR/float_cmp.rs:65:5
+   |
+LL |     ONE as f64 != 2.0;
+   |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() > error`
+   |
+   = note: `-D clippy::float-cmp` implied by `-D warnings`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64`
+  --> $DIR/float_cmp.rs:70:5
+   |
+LL |     x == 1.0;
+   |     ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64`
+  --> $DIR/float_cmp.rs:73:5
+   |
+LL |     twice(x) != twice(ONE as f64);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() > error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64`
+  --> $DIR/float_cmp.rs:93:5
+   |
+LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` arrays
+  --> $DIR/float_cmp.rs:98:5
+   |
+LL |     a1 == a2;
+   |     ^^^^^^^^
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64`
+  --> $DIR/float_cmp.rs:99:5
+   |
+LL |     a1[0] == a2[0];
+   |     ^^^^^^^^^^^^^^ help: consider comparing them within some error: `(a1[0] - a2[0]).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs
new file mode 100644
index 00000000000..dfc025558a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_cmp_const.rs
@@ -0,0 +1,62 @@
+// does not test any rustfixable lints
+
+#![warn(clippy::float_cmp_const)]
+#![allow(clippy::float_cmp)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
+
+const ONE: f32 = 1.0;
+const TWO: f32 = 2.0;
+
+fn eq_one(x: f32) -> bool {
+    if x.is_nan() {
+        false
+    } else {
+        x == ONE
+    } // no error, inside "eq" fn
+}
+
+fn main() {
+    // has errors
+    1f32 == ONE;
+    TWO == ONE;
+    TWO != ONE;
+    ONE + ONE == TWO;
+    let x = 1;
+    x as f32 == ONE;
+
+    let v = 0.9;
+    v == ONE;
+    v != ONE;
+
+    // no errors, lower than or greater than comparisons
+    v < ONE;
+    v > ONE;
+    v <= ONE;
+    v >= ONE;
+
+    // no errors, zero and infinity values
+    ONE != 0f32;
+    TWO == 0f32;
+    ONE != f32::INFINITY;
+    ONE == f32::NEG_INFINITY;
+
+    // no errors, but will warn clippy::float_cmp if '#![allow(float_cmp)]' above is removed
+    let w = 1.1;
+    v == w;
+    v != w;
+    v == 1.0;
+    v != 1.0;
+
+    const ZERO_ARRAY: [f32; 3] = [0.0, 0.0, 0.0];
+    const ZERO_INF_ARRAY: [f32; 3] = [0.0, ::std::f32::INFINITY, ::std::f32::NEG_INFINITY];
+    const NON_ZERO_ARRAY: [f32; 3] = [0.0, 0.1, 0.2];
+    const NON_ZERO_ARRAY2: [f32; 3] = [0.2, 0.1, 0.0];
+
+    // no errors, zero and infinity values
+    NON_ZERO_ARRAY[0] == NON_ZERO_ARRAY2[1]; // lhs is 0.0
+    ZERO_ARRAY == NON_ZERO_ARRAY; // lhs is all zeros
+    ZERO_INF_ARRAY == NON_ZERO_ARRAY; // lhs is all zeros or infinities
+
+    // has errors
+    NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
+}
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr
new file mode 100644
index 00000000000..19dc4a284b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr
@@ -0,0 +1,67 @@
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:20:5
+   |
+LL |     1f32 == ONE;
+   |     ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error`
+   |
+   = note: `-D clippy::float-cmp-const` implied by `-D warnings`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:21:5
+   |
+LL |     TWO == ONE;
+   |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:22:5
+   |
+LL |     TWO != ONE;
+   |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() > error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:23:5
+   |
+LL |     ONE + ONE == TWO;
+   |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:25:5
+   |
+LL |     x as f32 == ONE;
+   |     ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(x as f32 - ONE).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:28:5
+   |
+LL |     v == ONE;
+   |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant
+  --> $DIR/float_cmp_const.rs:29:5
+   |
+LL |     v != ONE;
+   |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() > error`
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: strict comparison of `f32` or `f64` constant arrays
+  --> $DIR/float_cmp_const.rs:61:5
+   |
+LL |     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed
new file mode 100644
index 00000000000..b623e4988e7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed
@@ -0,0 +1,98 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+struct A {
+    a: f64,
+    b: f64,
+}
+
+fn fake_abs1(num: f64) -> f64 {
+    num.abs()
+}
+
+fn fake_abs2(num: f64) -> f64 {
+    num.abs()
+}
+
+fn fake_abs3(a: A) -> f64 {
+    a.a.abs()
+}
+
+fn fake_abs4(num: f64) -> f64 {
+    num.abs()
+}
+
+fn fake_abs5(a: A) -> f64 {
+    a.a.abs()
+}
+
+fn fake_nabs1(num: f64) -> f64 {
+    -num.abs()
+}
+
+fn fake_nabs2(num: f64) -> f64 {
+    -num.abs()
+}
+
+fn fake_nabs3(a: A) -> A {
+    A {
+        a: -a.a.abs(),
+        b: a.b,
+    }
+}
+
+fn not_fake_abs1(num: f64) -> f64 {
+    if num > 0.0 {
+        num
+    } else {
+        -num - 1f64
+    }
+}
+
+fn not_fake_abs2(num: f64) -> f64 {
+    if num > 0.0 {
+        num + 1.0
+    } else {
+        -(num + 1.0)
+    }
+}
+
+fn not_fake_abs3(num1: f64, num2: f64) -> f64 {
+    if num1 > 0.0 {
+        num2
+    } else {
+        -num2
+    }
+}
+
+fn not_fake_abs4(a: A) -> f64 {
+    if a.a > 0.0 {
+        a.b
+    } else {
+        -a.b
+    }
+}
+
+fn not_fake_abs5(a: A) -> f64 {
+    if a.a > 0.0 {
+        a.a
+    } else {
+        -a.b
+    }
+}
+
+fn main() {
+    fake_abs1(5.0);
+    fake_abs2(5.0);
+    fake_abs3(A { a: 5.0, b: 5.0 });
+    fake_abs4(5.0);
+    fake_abs5(A { a: 5.0, b: 5.0 });
+    fake_nabs1(5.0);
+    fake_nabs2(5.0);
+    fake_nabs3(A { a: 5.0, b: 5.0 });
+    not_fake_abs1(5.0);
+    not_fake_abs2(5.0);
+    not_fake_abs3(5.0, 5.0);
+    not_fake_abs4(A { a: 5.0, b: 5.0 });
+    not_fake_abs5(A { a: 5.0, b: 5.0 });
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs
new file mode 100644
index 00000000000..cbf9c94e41e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_abs.rs
@@ -0,0 +1,126 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+struct A {
+    a: f64,
+    b: f64,
+}
+
+fn fake_abs1(num: f64) -> f64 {
+    if num >= 0.0 {
+        num
+    } else {
+        -num
+    }
+}
+
+fn fake_abs2(num: f64) -> f64 {
+    if 0.0 < num {
+        num
+    } else {
+        -num
+    }
+}
+
+fn fake_abs3(a: A) -> f64 {
+    if a.a > 0.0 {
+        a.a
+    } else {
+        -a.a
+    }
+}
+
+fn fake_abs4(num: f64) -> f64 {
+    if 0.0 >= num {
+        -num
+    } else {
+        num
+    }
+}
+
+fn fake_abs5(a: A) -> f64 {
+    if a.a < 0.0 {
+        -a.a
+    } else {
+        a.a
+    }
+}
+
+fn fake_nabs1(num: f64) -> f64 {
+    if num < 0.0 {
+        num
+    } else {
+        -num
+    }
+}
+
+fn fake_nabs2(num: f64) -> f64 {
+    if 0.0 >= num {
+        num
+    } else {
+        -num
+    }
+}
+
+fn fake_nabs3(a: A) -> A {
+    A {
+        a: if a.a >= 0.0 { -a.a } else { a.a },
+        b: a.b,
+    }
+}
+
+fn not_fake_abs1(num: f64) -> f64 {
+    if num > 0.0 {
+        num
+    } else {
+        -num - 1f64
+    }
+}
+
+fn not_fake_abs2(num: f64) -> f64 {
+    if num > 0.0 {
+        num + 1.0
+    } else {
+        -(num + 1.0)
+    }
+}
+
+fn not_fake_abs3(num1: f64, num2: f64) -> f64 {
+    if num1 > 0.0 {
+        num2
+    } else {
+        -num2
+    }
+}
+
+fn not_fake_abs4(a: A) -> f64 {
+    if a.a > 0.0 {
+        a.b
+    } else {
+        -a.b
+    }
+}
+
+fn not_fake_abs5(a: A) -> f64 {
+    if a.a > 0.0 {
+        a.a
+    } else {
+        -a.b
+    }
+}
+
+fn main() {
+    fake_abs1(5.0);
+    fake_abs2(5.0);
+    fake_abs3(A { a: 5.0, b: 5.0 });
+    fake_abs4(5.0);
+    fake_abs5(A { a: 5.0, b: 5.0 });
+    fake_nabs1(5.0);
+    fake_nabs2(5.0);
+    fake_nabs3(A { a: 5.0, b: 5.0 });
+    not_fake_abs1(5.0);
+    not_fake_abs2(5.0);
+    not_fake_abs3(5.0, 5.0);
+    not_fake_abs4(A { a: 5.0, b: 5.0 });
+    not_fake_abs5(A { a: 5.0, b: 5.0 });
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.stderr b/src/tools/clippy/tests/ui/floating_point_abs.stderr
new file mode 100644
index 00000000000..74a71f2ca7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_abs.stderr
@@ -0,0 +1,80 @@
+error: manual implementation of `abs` method
+  --> $DIR/floating_point_abs.rs:10:5
+   |
+LL | /     if num >= 0.0 {
+LL | |         num
+LL | |     } else {
+LL | |         -num
+LL | |     }
+   | |_____^ help: try: `num.abs()`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: manual implementation of `abs` method
+  --> $DIR/floating_point_abs.rs:18:5
+   |
+LL | /     if 0.0 < num {
+LL | |         num
+LL | |     } else {
+LL | |         -num
+LL | |     }
+   | |_____^ help: try: `num.abs()`
+
+error: manual implementation of `abs` method
+  --> $DIR/floating_point_abs.rs:26:5
+   |
+LL | /     if a.a > 0.0 {
+LL | |         a.a
+LL | |     } else {
+LL | |         -a.a
+LL | |     }
+   | |_____^ help: try: `a.a.abs()`
+
+error: manual implementation of `abs` method
+  --> $DIR/floating_point_abs.rs:34:5
+   |
+LL | /     if 0.0 >= num {
+LL | |         -num
+LL | |     } else {
+LL | |         num
+LL | |     }
+   | |_____^ help: try: `num.abs()`
+
+error: manual implementation of `abs` method
+  --> $DIR/floating_point_abs.rs:42:5
+   |
+LL | /     if a.a < 0.0 {
+LL | |         -a.a
+LL | |     } else {
+LL | |         a.a
+LL | |     }
+   | |_____^ help: try: `a.a.abs()`
+
+error: manual implementation of negation of `abs` method
+  --> $DIR/floating_point_abs.rs:50:5
+   |
+LL | /     if num < 0.0 {
+LL | |         num
+LL | |     } else {
+LL | |         -num
+LL | |     }
+   | |_____^ help: try: `-num.abs()`
+
+error: manual implementation of negation of `abs` method
+  --> $DIR/floating_point_abs.rs:58:5
+   |
+LL | /     if 0.0 >= num {
+LL | |         num
+LL | |     } else {
+LL | |         -num
+LL | |     }
+   | |_____^ help: try: `-num.abs()`
+
+error: manual implementation of negation of `abs` method
+  --> $DIR/floating_point_abs.rs:67:12
+   |
+LL |         a: if a.a >= 0.0 { -a.a } else { a.a },
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-a.a.abs()`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed
new file mode 100644
index 00000000000..ae7805fdf01
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::imprecise_flops)]
+
+fn main() {
+    let x = 2f32;
+    let _ = x.exp_m1();
+    let _ = x.exp_m1() + 2.0;
+    // Cases where the lint shouldn't be applied
+    let _ = x.exp() - 2.0;
+    let _ = x.exp() - 1.0 * 2.0;
+
+    let x = 2f64;
+    let _ = x.exp_m1();
+    let _ = x.exp_m1() + 2.0;
+    // Cases where the lint shouldn't be applied
+    let _ = x.exp() - 2.0;
+    let _ = x.exp() - 1.0 * 2.0;
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs
new file mode 100644
index 00000000000..27e0b9bcbc9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_exp.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::imprecise_flops)]
+
+fn main() {
+    let x = 2f32;
+    let _ = x.exp() - 1.0;
+    let _ = x.exp() - 1.0 + 2.0;
+    // Cases where the lint shouldn't be applied
+    let _ = x.exp() - 2.0;
+    let _ = x.exp() - 1.0 * 2.0;
+
+    let x = 2f64;
+    let _ = x.exp() - 1.0;
+    let _ = x.exp() - 1.0 + 2.0;
+    // Cases where the lint shouldn't be applied
+    let _ = x.exp() - 2.0;
+    let _ = x.exp() - 1.0 * 2.0;
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr
new file mode 100644
index 00000000000..5cd999ad47c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr
@@ -0,0 +1,28 @@
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:6:13
+   |
+LL |     let _ = x.exp() - 1.0;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
+   |
+   = note: `-D clippy::imprecise-flops` implied by `-D warnings`
+
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:7:13
+   |
+LL |     let _ = x.exp() - 1.0 + 2.0;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
+
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:13:13
+   |
+LL |     let _ = x.exp() - 1.0;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
+
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:14:13
+   |
+LL |     let _ = x.exp() - 1.0 + 2.0;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed
new file mode 100644
index 00000000000..42c5e5d2bae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_log.fixed
@@ -0,0 +1,58 @@
+// run-rustfix
+#![allow(dead_code, clippy::double_parens)]
+#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+
+const TWO: f32 = 2.0;
+const E: f32 = std::f32::consts::E;
+
+fn check_log_base() {
+    let x = 1f32;
+    let _ = x.log2();
+    let _ = x.log10();
+    let _ = x.ln();
+    let _ = x.log2();
+    let _ = x.ln();
+
+    let x = 1f64;
+    let _ = x.log2();
+    let _ = x.log10();
+    let _ = x.ln();
+}
+
+fn check_ln1p() {
+    let x = 1f32;
+    let _ = 2.0f32.ln_1p();
+    let _ = 2.0f32.ln_1p();
+    let _ = x.ln_1p();
+    let _ = (x / 2.0).ln_1p();
+    let _ = x.powi(2).ln_1p();
+    let _ = (x.powi(2) / 2.0).ln_1p();
+    let _ = ((std::f32::consts::E - 1.0)).ln_1p();
+    let _ = x.ln_1p();
+    let _ = x.powi(2).ln_1p();
+    let _ = (x + 2.0).ln_1p();
+    let _ = (x / 2.0).ln_1p();
+    // Cases where the lint shouldn't be applied
+    let _ = (1.0 + x + 2.0).ln();
+    let _ = (x + 1.0 + 2.0).ln();
+    let _ = (x + 1.0 / 2.0).ln();
+    let _ = (1.0 + x - 2.0).ln();
+
+    let x = 1f64;
+    let _ = 2.0f64.ln_1p();
+    let _ = 2.0f64.ln_1p();
+    let _ = x.ln_1p();
+    let _ = (x / 2.0).ln_1p();
+    let _ = x.powi(2).ln_1p();
+    let _ = x.ln_1p();
+    let _ = x.powi(2).ln_1p();
+    let _ = (x + 2.0).ln_1p();
+    let _ = (x / 2.0).ln_1p();
+    // Cases where the lint shouldn't be applied
+    let _ = (1.0 + x + 2.0).ln();
+    let _ = (x + 1.0 + 2.0).ln();
+    let _ = (x + 1.0 / 2.0).ln();
+    let _ = (1.0 + x - 2.0).ln();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs
new file mode 100644
index 00000000000..8be0d9ad56f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_log.rs
@@ -0,0 +1,58 @@
+// run-rustfix
+#![allow(dead_code, clippy::double_parens)]
+#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+
+const TWO: f32 = 2.0;
+const E: f32 = std::f32::consts::E;
+
+fn check_log_base() {
+    let x = 1f32;
+    let _ = x.log(2f32);
+    let _ = x.log(10f32);
+    let _ = x.log(std::f32::consts::E);
+    let _ = x.log(TWO);
+    let _ = x.log(E);
+
+    let x = 1f64;
+    let _ = x.log(2f64);
+    let _ = x.log(10f64);
+    let _ = x.log(std::f64::consts::E);
+}
+
+fn check_ln1p() {
+    let x = 1f32;
+    let _ = (1f32 + 2.).ln();
+    let _ = (1f32 + 2.0).ln();
+    let _ = (1.0 + x).ln();
+    let _ = (1.0 + x / 2.0).ln();
+    let _ = (1.0 + x.powi(2)).ln();
+    let _ = (1.0 + x.powi(2) / 2.0).ln();
+    let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
+    let _ = (x + 1.0).ln();
+    let _ = (x.powi(2) + 1.0).ln();
+    let _ = (x + 2.0 + 1.0).ln();
+    let _ = (x / 2.0 + 1.0).ln();
+    // Cases where the lint shouldn't be applied
+    let _ = (1.0 + x + 2.0).ln();
+    let _ = (x + 1.0 + 2.0).ln();
+    let _ = (x + 1.0 / 2.0).ln();
+    let _ = (1.0 + x - 2.0).ln();
+
+    let x = 1f64;
+    let _ = (1f64 + 2.).ln();
+    let _ = (1f64 + 2.0).ln();
+    let _ = (1.0 + x).ln();
+    let _ = (1.0 + x / 2.0).ln();
+    let _ = (1.0 + x.powi(2)).ln();
+    let _ = (x + 1.0).ln();
+    let _ = (x.powi(2) + 1.0).ln();
+    let _ = (x + 2.0 + 1.0).ln();
+    let _ = (x / 2.0 + 1.0).ln();
+    // Cases where the lint shouldn't be applied
+    let _ = (1.0 + x + 2.0).ln();
+    let _ = (x + 1.0 + 2.0).ln();
+    let _ = (x + 1.0 / 2.0).ln();
+    let _ = (1.0 + x - 2.0).ln();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr
new file mode 100644
index 00000000000..943fbdb0b83
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_log.stderr
@@ -0,0 +1,174 @@
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:10:13
+   |
+LL |     let _ = x.log(2f32);
+   |             ^^^^^^^^^^^ help: consider using: `x.log2()`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:11:13
+   |
+LL |     let _ = x.log(10f32);
+   |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:12:13
+   |
+LL |     let _ = x.log(std::f32::consts::E);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:13:13
+   |
+LL |     let _ = x.log(TWO);
+   |             ^^^^^^^^^^ help: consider using: `x.log2()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:14:13
+   |
+LL |     let _ = x.log(E);
+   |             ^^^^^^^^ help: consider using: `x.ln()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:17:13
+   |
+LL |     let _ = x.log(2f64);
+   |             ^^^^^^^^^^^ help: consider using: `x.log2()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:18:13
+   |
+LL |     let _ = x.log(10f64);
+   |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:19:13
+   |
+LL |     let _ = x.log(std::f64::consts::E);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:24:13
+   |
+LL |     let _ = (1f32 + 2.).ln();
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
+   |
+   = note: `-D clippy::imprecise-flops` implied by `-D warnings`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:25:13
+   |
+LL |     let _ = (1f32 + 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:26:13
+   |
+LL |     let _ = (1.0 + x).ln();
+   |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:27:13
+   |
+LL |     let _ = (1.0 + x / 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:28:13
+   |
+LL |     let _ = (1.0 + x.powi(2)).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:29:13
+   |
+LL |     let _ = (1.0 + x.powi(2) / 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:30:13
+   |
+LL |     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:31:13
+   |
+LL |     let _ = (x + 1.0).ln();
+   |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:32:13
+   |
+LL |     let _ = (x.powi(2) + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:33:13
+   |
+LL |     let _ = (x + 2.0 + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:34:13
+   |
+LL |     let _ = (x / 2.0 + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:42:13
+   |
+LL |     let _ = (1f64 + 2.).ln();
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:43:13
+   |
+LL |     let _ = (1f64 + 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:44:13
+   |
+LL |     let _ = (1.0 + x).ln();
+   |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:45:13
+   |
+LL |     let _ = (1.0 + x / 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:46:13
+   |
+LL |     let _ = (1.0 + x.powi(2)).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:47:13
+   |
+LL |     let _ = (x + 1.0).ln();
+   |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:48:13
+   |
+LL |     let _ = (x.powi(2) + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:49:13
+   |
+LL |     let _ = (x + 2.0 + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
+
+error: ln(1 + x) can be computed more accurately
+  --> $DIR/floating_point_log.rs:50:13
+   |
+LL |     let _ = (x / 2.0 + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
+
+error: aborting due to 28 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
new file mode 100644
index 00000000000..e343c37740d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let a: f64 = 1234.567;
+    let b: f64 = 45.67834;
+    let c: f64 = 0.0004;
+    let d: f64 = 0.0001;
+
+    let _ = a.mul_add(b, c);
+    let _ = a.mul_add(b, c);
+    let _ = 2.0f64.mul_add(4.0, a);
+    let _ = 2.0f64.mul_add(4., a);
+
+    let _ = a.mul_add(b, c);
+    let _ = a.mul_add(b, c);
+    let _ = (a * b).mul_add(c, d);
+
+    let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c;
+    let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64);
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
new file mode 100644
index 00000000000..810f929c856
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let a: f64 = 1234.567;
+    let b: f64 = 45.67834;
+    let c: f64 = 0.0004;
+    let d: f64 = 0.0001;
+
+    let _ = a * b + c;
+    let _ = c + a * b;
+    let _ = a + 2.0 * 4.0;
+    let _ = a + 2. * 4.;
+
+    let _ = (a * b) + c;
+    let _ = c + (a * b);
+    let _ = a * b * c + d;
+
+    let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
+    let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
new file mode 100644
index 00000000000..2dfbf562d15
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
@@ -0,0 +1,58 @@
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:10:13
+   |
+LL |     let _ = a * b + c;
+   |             ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:11:13
+   |
+LL |     let _ = c + a * b;
+   |             ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:12:13
+   |
+LL |     let _ = a + 2.0 * 4.0;
+   |             ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:13:13
+   |
+LL |     let _ = a + 2. * 4.;
+   |             ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:15:13
+   |
+LL |     let _ = (a * b) + c;
+   |             ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:16:13
+   |
+LL |     let _ = c + (a * b);
+   |             ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:17:13
+   |
+LL |     let _ = a * b * c + d;
+   |             ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:19:13
+   |
+LL |     let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:20:13
+   |
+LL |     let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed
new file mode 100644
index 00000000000..78a9d44829b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+
+fn main() {
+    let x = 3f32;
+    let _ = x.exp2();
+    let _ = 3.1f32.exp2();
+    let _ = (-3.1f32).exp2();
+    let _ = x.exp();
+    let _ = 3.1f32.exp();
+    let _ = (-3.1f32).exp();
+    let _ = x.sqrt();
+    let _ = x.cbrt();
+    let _ = x.powi(2);
+    let _ = x.powi(-2);
+    let _ = x.powi(16_777_215);
+    let _ = x.powi(-16_777_215);
+    // Cases where the lint shouldn't be applied
+    let _ = x.powf(2.1);
+    let _ = x.powf(-2.1);
+    let _ = x.powf(16_777_216.0);
+    let _ = x.powf(-16_777_216.0);
+
+    let x = 3f64;
+    let _ = x.exp2();
+    let _ = 3.1f64.exp2();
+    let _ = (-3.1f64).exp2();
+    let _ = x.exp();
+    let _ = 3.1f64.exp();
+    let _ = (-3.1f64).exp();
+    let _ = x.sqrt();
+    let _ = x.cbrt();
+    let _ = x.powi(2);
+    let _ = x.powi(-2);
+    let _ = x.powi(-2_147_483_648);
+    let _ = x.powi(2_147_483_647);
+    // Cases where the lint shouldn't be applied
+    let _ = x.powf(2.1);
+    let _ = x.powf(-2.1);
+    let _ = x.powf(-2_147_483_649.0);
+    let _ = x.powf(2_147_483_648.0);
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs
new file mode 100644
index 00000000000..dbc1cac5cb4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_powf.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+
+fn main() {
+    let x = 3f32;
+    let _ = 2f32.powf(x);
+    let _ = 2f32.powf(3.1);
+    let _ = 2f32.powf(-3.1);
+    let _ = std::f32::consts::E.powf(x);
+    let _ = std::f32::consts::E.powf(3.1);
+    let _ = std::f32::consts::E.powf(-3.1);
+    let _ = x.powf(1.0 / 2.0);
+    let _ = x.powf(1.0 / 3.0);
+    let _ = x.powf(2.0);
+    let _ = x.powf(-2.0);
+    let _ = x.powf(16_777_215.0);
+    let _ = x.powf(-16_777_215.0);
+    // Cases where the lint shouldn't be applied
+    let _ = x.powf(2.1);
+    let _ = x.powf(-2.1);
+    let _ = x.powf(16_777_216.0);
+    let _ = x.powf(-16_777_216.0);
+
+    let x = 3f64;
+    let _ = 2f64.powf(x);
+    let _ = 2f64.powf(3.1);
+    let _ = 2f64.powf(-3.1);
+    let _ = std::f64::consts::E.powf(x);
+    let _ = std::f64::consts::E.powf(3.1);
+    let _ = std::f64::consts::E.powf(-3.1);
+    let _ = x.powf(1.0 / 2.0);
+    let _ = x.powf(1.0 / 3.0);
+    let _ = x.powf(2.0);
+    let _ = x.powf(-2.0);
+    let _ = x.powf(-2_147_483_648.0);
+    let _ = x.powf(2_147_483_647.0);
+    // Cases where the lint shouldn't be applied
+    let _ = x.powf(2.1);
+    let _ = x.powf(-2.1);
+    let _ = x.powf(-2_147_483_649.0);
+    let _ = x.powf(2_147_483_648.0);
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr
new file mode 100644
index 00000000000..ad5163f0079
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr
@@ -0,0 +1,150 @@
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:6:13
+   |
+LL |     let _ = 2f32.powf(x);
+   |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:7:13
+   |
+LL |     let _ = 2f32.powf(3.1);
+   |             ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:8:13
+   |
+LL |     let _ = 2f32.powf(-3.1);
+   |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:9:13
+   |
+LL |     let _ = std::f32::consts::E.powf(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:10:13
+   |
+LL |     let _ = std::f32::consts::E.powf(3.1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:11:13
+   |
+LL |     let _ = std::f32::consts::E.powf(-3.1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()`
+
+error: square-root of a number can be computed more efficiently and accurately
+  --> $DIR/floating_point_powf.rs:12:13
+   |
+LL |     let _ = x.powf(1.0 / 2.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
+
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:13:13
+   |
+LL |     let _ = x.powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
+   |
+   = note: `-D clippy::imprecise-flops` implied by `-D warnings`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:14:13
+   |
+LL |     let _ = x.powf(2.0);
+   |             ^^^^^^^^^^^ help: consider using: `x.powi(2)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:15:13
+   |
+LL |     let _ = x.powf(-2.0);
+   |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:16:13
+   |
+LL |     let _ = x.powf(16_777_215.0);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:17:13
+   |
+LL |     let _ = x.powf(-16_777_215.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:25:13
+   |
+LL |     let _ = 2f64.powf(x);
+   |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:26:13
+   |
+LL |     let _ = 2f64.powf(3.1);
+   |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:27:13
+   |
+LL |     let _ = 2f64.powf(-3.1);
+   |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:28:13
+   |
+LL |     let _ = std::f64::consts::E.powf(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:29:13
+   |
+LL |     let _ = std::f64::consts::E.powf(3.1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> $DIR/floating_point_powf.rs:30:13
+   |
+LL |     let _ = std::f64::consts::E.powf(-3.1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
+
+error: square-root of a number can be computed more efficiently and accurately
+  --> $DIR/floating_point_powf.rs:31:13
+   |
+LL |     let _ = x.powf(1.0 / 2.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
+
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:32:13
+   |
+LL |     let _ = x.powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:33:13
+   |
+LL |     let _ = x.powf(2.0);
+   |             ^^^^^^^^^^^ help: consider using: `x.powi(2)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:34:13
+   |
+LL |     let _ = x.powf(-2.0);
+   |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:35:13
+   |
+LL |     let _ = x.powf(-2_147_483_648.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:36:13
+   |
+LL |     let _ = x.powf(2_147_483_647.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/fn_address_comparisons.rs b/src/tools/clippy/tests/ui/fn_address_comparisons.rs
new file mode 100644
index 00000000000..362dcb4fd80
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_address_comparisons.rs
@@ -0,0 +1,20 @@
+use std::fmt::Debug;
+use std::ptr;
+use std::rc::Rc;
+use std::sync::Arc;
+
+fn a() {}
+
+#[warn(clippy::fn_address_comparisons)]
+fn main() {
+    type F = fn();
+    let f: F = a;
+    let g: F = f;
+
+    // These should fail:
+    let _ = f == a;
+    let _ = f != a;
+
+    // These should be fine:
+    let _ = f == g;
+}
diff --git a/src/tools/clippy/tests/ui/fn_address_comparisons.stderr b/src/tools/clippy/tests/ui/fn_address_comparisons.stderr
new file mode 100644
index 00000000000..9c1b5419a43
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_address_comparisons.stderr
@@ -0,0 +1,16 @@
+error: comparing with a non-unique address of a function item
+  --> $DIR/fn_address_comparisons.rs:15:13
+   |
+LL |     let _ = f == a;
+   |             ^^^^^^
+   |
+   = note: `-D clippy::fn-address-comparisons` implied by `-D warnings`
+
+error: comparing with a non-unique address of a function item
+  --> $DIR/fn_address_comparisons.rs:16:13
+   |
+LL |     let _ = f != a;
+   |             ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs b/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
new file mode 100644
index 00000000000..7d6fd607e65
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
@@ -0,0 +1,44 @@
+#![warn(clippy::fn_params_excessive_bools)]
+
+extern "C" {
+    fn f(_: bool, _: bool, _: bool, _: bool);
+}
+
+macro_rules! foo {
+    () => {
+        fn fff(_: bool, _: bool, _: bool, _: bool) {}
+    };
+}
+
+foo!();
+
+#[no_mangle]
+extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {}
+fn g(_: bool, _: bool, _: bool, _: bool) {}
+fn h(_: bool, _: bool, _: bool) {}
+fn e(_: S, _: S, _: Box<S>, _: Vec<u32>) {}
+fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
+
+struct S {}
+trait Trait {
+    fn f(_: bool, _: bool, _: bool, _: bool);
+    fn g(_: bool, _: bool, _: bool, _: Vec<u32>);
+}
+
+impl S {
+    fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
+    fn g(&self, _: bool, _: bool, _: bool) {}
+    #[no_mangle]
+    extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {}
+}
+
+impl Trait for S {
+    fn f(_: bool, _: bool, _: bool, _: bool) {}
+    fn g(_: bool, _: bool, _: bool, _: Vec<u32>) {}
+}
+
+fn main() {
+    fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
+        fn nn(_: bool, _: bool, _: bool, _: bool) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr
new file mode 100644
index 00000000000..4e5dbc261d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr
@@ -0,0 +1,53 @@
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:17:1
+   |
+LL | fn g(_: bool, _: bool, _: bool, _: bool) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
+   = help: consider refactoring bools into two-variant enums
+
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:20:1
+   |
+LL | fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider refactoring bools into two-variant enums
+
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:24:5
+   |
+LL |     fn f(_: bool, _: bool, _: bool, _: bool);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider refactoring bools into two-variant enums
+
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:29:5
+   |
+LL |     fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider refactoring bools into two-variant enums
+
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:41:5
+   |
+LL | /     fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
+LL | |         fn nn(_: bool, _: bool, _: bool, _: bool) {}
+LL | |     }
+   | |_____^
+   |
+   = help: consider refactoring bools into two-variant enums
+
+error: more than 3 bools in function parameters
+  --> $DIR/fn_params_excessive_bools.rs:42:9
+   |
+LL |         fn nn(_: bool, _: bool, _: bool, _: bool) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider refactoring bools into two-variant enums
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs
new file mode 100644
index 00000000000..a456c085c87
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs
@@ -0,0 +1,55 @@
+// ignore-32bit
+
+#![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> String {
+    String::new()
+}
+
+fn test_function_to_numeric_cast() {
+    let _ = foo as i8;
+    let _ = foo as i16;
+    let _ = foo as i32;
+    let _ = foo as i64;
+    let _ = foo as i128;
+    let _ = foo as isize;
+
+    let _ = foo as u8;
+    let _ = foo as u16;
+    let _ = foo as u32;
+    let _ = foo as u64;
+    let _ = foo as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = foo as usize;
+
+    // Cast `f` (a `FnDef`) to `fn()` should not warn
+    fn f() {}
+    let _ = f as fn();
+}
+
+fn test_function_var_to_numeric_cast() {
+    let abc: fn() -> String = foo;
+
+    let _ = abc as i8;
+    let _ = abc as i16;
+    let _ = abc as i32;
+    let _ = abc as i64;
+    let _ = abc as i128;
+    let _ = abc as isize;
+
+    let _ = abc as u8;
+    let _ = abc as u16;
+    let _ = abc as u32;
+    let _ = abc as u64;
+    let _ = abc as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = abc as usize;
+}
+
+fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
+    f as i32
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr
new file mode 100644
index 00000000000..e9549e157cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.stderr
@@ -0,0 +1,144 @@
+error: casting function pointer `foo` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:10:13
+   |
+LL |     let _ = foo as i8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:11:13
+   |
+LL |     let _ = foo as i16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:12:13
+   |
+LL |     let _ = foo as i32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i64`
+  --> $DIR/fn_to_numeric_cast.rs:13:13
+   |
+LL |     let _ = foo as i64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i128`
+  --> $DIR/fn_to_numeric_cast.rs:14:13
+   |
+LL |     let _ = foo as i128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `isize`
+  --> $DIR/fn_to_numeric_cast.rs:15:13
+   |
+LL |     let _ = foo as isize;
+   |             ^^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:17:13
+   |
+LL |     let _ = foo as u8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:18:13
+   |
+LL |     let _ = foo as u16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:19:13
+   |
+LL |     let _ = foo as u32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u64`
+  --> $DIR/fn_to_numeric_cast.rs:20:13
+   |
+LL |     let _ = foo as u64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u128`
+  --> $DIR/fn_to_numeric_cast.rs:21:13
+   |
+LL |     let _ = foo as u128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `abc` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:34:13
+   |
+LL |     let _ = abc as i8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:35:13
+   |
+LL |     let _ = abc as i16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:36:13
+   |
+LL |     let _ = abc as i32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i64`
+  --> $DIR/fn_to_numeric_cast.rs:37:13
+   |
+LL |     let _ = abc as i64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i128`
+  --> $DIR/fn_to_numeric_cast.rs:38:13
+   |
+LL |     let _ = abc as i128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `isize`
+  --> $DIR/fn_to_numeric_cast.rs:39:13
+   |
+LL |     let _ = abc as isize;
+   |             ^^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:41:13
+   |
+LL |     let _ = abc as u8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:42:13
+   |
+LL |     let _ = abc as u16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:43:13
+   |
+LL |     let _ = abc as u32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u64`
+  --> $DIR/fn_to_numeric_cast.rs:44:13
+   |
+LL |     let _ = abc as u64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u128`
+  --> $DIR/fn_to_numeric_cast.rs:45:13
+   |
+LL |     let _ = abc as u128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `f` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:52:5
+   |
+LL |     f as i32
+   |     ^^^^^^^^ help: try: `f as usize`
+
+error: aborting due to 23 previous errors
+
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs
new file mode 100644
index 00000000000..04ee985c086
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs
@@ -0,0 +1,55 @@
+// ignore-64bit
+
+#![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> String {
+    String::new()
+}
+
+fn test_function_to_numeric_cast() {
+    let _ = foo as i8;
+    let _ = foo as i16;
+    let _ = foo as i32;
+    let _ = foo as i64;
+    let _ = foo as i128;
+    let _ = foo as isize;
+
+    let _ = foo as u8;
+    let _ = foo as u16;
+    let _ = foo as u32;
+    let _ = foo as u64;
+    let _ = foo as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = foo as usize;
+
+    // Cast `f` (a `FnDef`) to `fn()` should not warn
+    fn f() {}
+    let _ = f as fn();
+}
+
+fn test_function_var_to_numeric_cast() {
+    let abc: fn() -> String = foo;
+
+    let _ = abc as i8;
+    let _ = abc as i16;
+    let _ = abc as i32;
+    let _ = abc as i64;
+    let _ = abc as i128;
+    let _ = abc as isize;
+
+    let _ = abc as u8;
+    let _ = abc as u16;
+    let _ = abc as u32;
+    let _ = abc as u64;
+    let _ = abc as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = abc as usize;
+}
+
+fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
+    f as i32
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr
new file mode 100644
index 00000000000..08dd611d675
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr
@@ -0,0 +1,144 @@
+error: casting function pointer `foo` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:10:13
+   |
+LL |     let _ = foo as i8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:11:13
+   |
+LL |     let _ = foo as i16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i32`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:12:13
+   |
+LL |     let _ = foo as i32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i64`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:13:13
+   |
+LL |     let _ = foo as i64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i128`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:14:13
+   |
+LL |     let _ = foo as i128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `isize`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:15:13
+   |
+LL |     let _ = foo as isize;
+   |             ^^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:17:13
+   |
+LL |     let _ = foo as u8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:18:13
+   |
+LL |     let _ = foo as u16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u32`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:19:13
+   |
+LL |     let _ = foo as u32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u64`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:20:13
+   |
+LL |     let _ = foo as u64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u128`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:21:13
+   |
+LL |     let _ = foo as u128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `abc` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:34:13
+   |
+LL |     let _ = abc as i8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:35:13
+   |
+LL |     let _ = abc as i16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i32`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:36:13
+   |
+LL |     let _ = abc as i32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i64`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:37:13
+   |
+LL |     let _ = abc as i64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i128`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:38:13
+   |
+LL |     let _ = abc as i128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `isize`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:39:13
+   |
+LL |     let _ = abc as isize;
+   |             ^^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:41:13
+   |
+LL |     let _ = abc as u8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast_32bit.rs:42:13
+   |
+LL |     let _ = abc as u16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u32`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:43:13
+   |
+LL |     let _ = abc as u32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u64`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:44:13
+   |
+LL |     let _ = abc as u64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u128`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:45:13
+   |
+LL |     let _ = abc as u128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `f` to `i32`
+  --> $DIR/fn_to_numeric_cast_32bit.rs:52:5
+   |
+LL |     f as i32
+   |     ^^^^^^^^ help: try: `f as usize`
+
+error: aborting due to 23 previous errors
+
diff --git a/src/tools/clippy/tests/ui/for_kv_map.rs b/src/tools/clippy/tests/ui/for_kv_map.rs
new file mode 100644
index 00000000000..39a8d960a7e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_kv_map.rs
@@ -0,0 +1,50 @@
+#![warn(clippy::for_kv_map)]
+#![allow(clippy::used_underscore_binding)]
+
+use std::collections::*;
+use std::rc::Rc;
+
+fn main() {
+    let m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &m {
+        let _v = v;
+    }
+
+    let m: Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
+    for (_, v) in &*m {
+        let _v = v;
+        // Here the `*` is not actually necessary, but the test tests that we don't
+        // suggest
+        // `in *m.values()` as we used to
+    }
+
+    let mut m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &mut m {
+        let _v = v;
+    }
+
+    let m: &mut HashMap<u64, u64> = &mut HashMap::new();
+    for (_, v) in &mut *m {
+        let _v = v;
+    }
+
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    for (k, _value) in rm {
+        let _k = k;
+    }
+
+    // The following should not produce warnings.
+
+    let m: HashMap<u64, u64> = HashMap::new();
+    // No error, _value is actually used
+    for (k, _value) in &m {
+        let _ = _value;
+        let _k = k;
+    }
+
+    let m: HashMap<u64, String> = Default::default();
+    for (_, v) in m {
+        let _v = v;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/for_kv_map.stderr b/src/tools/clippy/tests/ui/for_kv_map.stderr
new file mode 100644
index 00000000000..241758c542c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_kv_map.stderr
@@ -0,0 +1,58 @@
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:9:19
+   |
+LL |     for (_, v) in &m {
+   |                   ^^
+   |
+   = note: `-D clippy::for-kv-map` implied by `-D warnings`
+help: use the corresponding method
+   |
+LL |     for v in m.values() {
+   |         ^    ^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:14:19
+   |
+LL |     for (_, v) in &*m {
+   |                   ^^^
+   |
+help: use the corresponding method
+   |
+LL |     for v in (*m).values() {
+   |         ^    ^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:22:19
+   |
+LL |     for (_, v) in &mut m {
+   |                   ^^^^^^
+   |
+help: use the corresponding method
+   |
+LL |     for v in m.values_mut() {
+   |         ^    ^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:27:19
+   |
+LL |     for (_, v) in &mut *m {
+   |                   ^^^^^^^
+   |
+help: use the corresponding method
+   |
+LL |     for v in (*m).values_mut() {
+   |         ^    ^^^^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's keys
+  --> $DIR/for_kv_map.rs:33:24
+   |
+LL |     for (k, _value) in rm {
+   |                        ^^
+   |
+help: use the corresponding method
+   |
+LL |     for k in rm.keys() {
+   |         ^    ^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.fixed b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
new file mode 100644
index 00000000000..5fc84ada9ef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
@@ -0,0 +1,337 @@
+// run-rustfix
+
+#![allow(dead_code, unused)]
+
+use std::collections::*;
+
+#[warn(clippy::all)]
+struct Unrelated(Vec<u8>);
+impl Unrelated {
+    fn next(&self) -> std::slice::Iter<u8> {
+        self.0.iter()
+    }
+
+    fn iter(&self) -> std::slice::Iter<u8> {
+        self.0.iter()
+    }
+}
+
+#[warn(
+    clippy::needless_range_loop,
+    clippy::explicit_iter_loop,
+    clippy::explicit_into_iter_loop,
+    clippy::iter_next_loop,
+    clippy::reverse_range_loop,
+    clippy::for_kv_map
+)]
+#[allow(
+    clippy::linkedlist,
+    clippy::shadow_unrelated,
+    clippy::unnecessary_mut_passed,
+    clippy::similar_names
+)]
+#[allow(clippy::many_single_char_names, unused_variables)]
+fn main() {
+    const MAX_LEN: usize = 42;
+    let mut vec = vec![1, 2, 3, 4];
+
+    for i in (0..10).rev() {
+        println!("{}", i);
+    }
+
+    for i in (0..=10).rev() {
+        println!("{}", i);
+    }
+
+    for i in (0..MAX_LEN).rev() {
+        println!("{}", i);
+    }
+
+    for i in 5..=5 {
+        // not an error, this is the range with only one element “5”
+        println!("{}", i);
+    }
+
+    for i in 0..10 {
+        // not an error, the start index is less than the end index
+        println!("{}", i);
+    }
+
+    for i in -10..0 {
+        // not an error
+        println!("{}", i);
+    }
+
+    for i in (10..0).map(|x| x * 2) {
+        // not an error, it can't be known what arbitrary methods do to a range
+        println!("{}", i);
+    }
+
+    // testing that the empty range lint folds constants
+    for i in (5 + 4..10).rev() {
+        println!("{}", i);
+    }
+
+    for i in ((3 - 1)..(5 + 2)).rev() {
+        println!("{}", i);
+    }
+
+    for i in (2 * 2)..(2 * 3) {
+        // no error, 4..6 is fine
+        println!("{}", i);
+    }
+
+    let x = 42;
+    for i in x..10 {
+        // no error, not constant-foldable
+        println!("{}", i);
+    }
+
+    // See #601
+    for i in 0..10 {
+        // no error, id_col does not exist outside the loop
+        let mut id_col = vec![0f64; 10];
+        id_col[i] = 1f64;
+    }
+
+    for _v in &vec {}
+
+    for _v in &mut vec {}
+
+    let out_vec = vec![1, 2, 3];
+    for _v in out_vec {}
+
+    for _v in &vec {} // these are fine
+    for _v in &mut vec {} // these are fine
+
+    for _v in &[1, 2, 3] {}
+
+    for _v in (&mut [1, 2, 3]).iter() {} // no error
+
+    for _v in &[0; 32] {}
+
+    for _v in [0; 33].iter() {} // no error
+
+    let ll: LinkedList<()> = LinkedList::new();
+    for _v in &ll {}
+
+    let vd: VecDeque<()> = VecDeque::new();
+    for _v in &vd {}
+
+    let bh: BinaryHeap<()> = BinaryHeap::new();
+    for _v in &bh {}
+
+    let hm: HashMap<(), ()> = HashMap::new();
+    for _v in &hm {}
+
+    let bt: BTreeMap<(), ()> = BTreeMap::new();
+    for _v in &bt {}
+
+    let hs: HashSet<()> = HashSet::new();
+    for _v in &hs {}
+
+    let bs: BTreeSet<()> = BTreeSet::new();
+    for _v in &bs {}
+
+    let u = Unrelated(vec![]);
+    for _v in u.next() {} // no error
+    for _v in u.iter() {} // no error
+
+    let mut out = vec![];
+    vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
+    let _y = vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine
+
+    // Loop with explicit counter variable
+
+    // Potential false positives
+    let mut _index = 0;
+    _index = 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    _index += 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    if true {
+        _index = 1
+    }
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    let mut _index = 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index *= 2;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index = 1;
+        _index += 1
+    }
+
+    let mut _index = 0;
+
+    for _v in &vec {
+        let mut _index = 0;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1;
+        _index = 0;
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        for _x in 0..1 {
+            _index += 1;
+        }
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for x in &vec {
+        if *x == 1 {
+            _index += 1
+        }
+    }
+
+    let mut _index = 0;
+    if true {
+        _index = 1
+    };
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 1;
+    if false {
+        _index = 0
+    };
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut index = 0;
+    {
+        let mut _x = &mut index;
+    }
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut index = 0;
+    for _v in &vec {
+        index += 1
+    }
+    println!("index: {}", index);
+
+    fn f<T>(_: &T, _: &T) -> bool {
+        unimplemented!()
+    }
+    fn g<T>(_: &mut [T], _: usize, _: usize) {
+        unimplemented!()
+    }
+    for i in 1..vec.len() {
+        if f(&vec[i - 1], &vec[i]) {
+            g(&mut vec, i - 1, i);
+        }
+    }
+
+    for mid in 1..vec.len() {
+        let (_, _) = vec.split_at(mid);
+    }
+}
+
+fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
+    let pivot = v.len() - 1;
+    let mut i = 0;
+    for j in 0..pivot {
+        if v[j] <= v[pivot] {
+            v.swap(i, j);
+            i += 1;
+        }
+    }
+    v.swap(i, pivot);
+    i
+}
+
+#[warn(clippy::needless_range_loop)]
+pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) {
+    // Same source and destination - don't trigger lint
+    for i in 0..dst.len() {
+        dst[d + i] = dst[s + i];
+    }
+}
+
+mod issue_2496 {
+    pub trait Handle {
+        fn new_for_index(index: usize) -> Self;
+        fn index(&self) -> usize;
+    }
+
+    pub fn test<H: Handle>() -> H {
+        for x in 0..5 {
+            let next_handle = H::new_for_index(x);
+            println!("{}", next_handle.index());
+        }
+        unimplemented!()
+    }
+}
+
+// explicit_into_iter_loop bad suggestions
+#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)]
+mod issue_4958 {
+    fn takes_iterator<T>(iterator: &T)
+    where
+        for<'a> &'a T: IntoIterator<Item = &'a String>,
+    {
+        for i in iterator {
+            println!("{}", i);
+        }
+    }
+
+    struct T;
+    impl IntoIterator for &T {
+        type Item = ();
+        type IntoIter = std::vec::IntoIter<Self::Item>;
+        fn into_iter(self) -> Self::IntoIter {
+            vec![].into_iter()
+        }
+    }
+
+    fn more_tests() {
+        let t = T;
+        let r = &t;
+        let rr = &&t;
+
+        // This case is handled by `explicit_iter_loop`. No idea why.
+        for _ in &t {}
+
+        for _ in r {}
+
+        // No suggestion for this.
+        // We'd have to suggest `for _ in *rr {}` which is less clear.
+        for _ in rr.into_iter() {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.rs b/src/tools/clippy/tests/ui/for_loop_fixable.rs
new file mode 100644
index 00000000000..4165b0dc004
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.rs
@@ -0,0 +1,337 @@
+// run-rustfix
+
+#![allow(dead_code, unused)]
+
+use std::collections::*;
+
+#[warn(clippy::all)]
+struct Unrelated(Vec<u8>);
+impl Unrelated {
+    fn next(&self) -> std::slice::Iter<u8> {
+        self.0.iter()
+    }
+
+    fn iter(&self) -> std::slice::Iter<u8> {
+        self.0.iter()
+    }
+}
+
+#[warn(
+    clippy::needless_range_loop,
+    clippy::explicit_iter_loop,
+    clippy::explicit_into_iter_loop,
+    clippy::iter_next_loop,
+    clippy::reverse_range_loop,
+    clippy::for_kv_map
+)]
+#[allow(
+    clippy::linkedlist,
+    clippy::shadow_unrelated,
+    clippy::unnecessary_mut_passed,
+    clippy::similar_names
+)]
+#[allow(clippy::many_single_char_names, unused_variables)]
+fn main() {
+    const MAX_LEN: usize = 42;
+    let mut vec = vec![1, 2, 3, 4];
+
+    for i in 10..0 {
+        println!("{}", i);
+    }
+
+    for i in 10..=0 {
+        println!("{}", i);
+    }
+
+    for i in MAX_LEN..0 {
+        println!("{}", i);
+    }
+
+    for i in 5..=5 {
+        // not an error, this is the range with only one element “5”
+        println!("{}", i);
+    }
+
+    for i in 0..10 {
+        // not an error, the start index is less than the end index
+        println!("{}", i);
+    }
+
+    for i in -10..0 {
+        // not an error
+        println!("{}", i);
+    }
+
+    for i in (10..0).map(|x| x * 2) {
+        // not an error, it can't be known what arbitrary methods do to a range
+        println!("{}", i);
+    }
+
+    // testing that the empty range lint folds constants
+    for i in 10..5 + 4 {
+        println!("{}", i);
+    }
+
+    for i in (5 + 2)..(3 - 1) {
+        println!("{}", i);
+    }
+
+    for i in (2 * 2)..(2 * 3) {
+        // no error, 4..6 is fine
+        println!("{}", i);
+    }
+
+    let x = 42;
+    for i in x..10 {
+        // no error, not constant-foldable
+        println!("{}", i);
+    }
+
+    // See #601
+    for i in 0..10 {
+        // no error, id_col does not exist outside the loop
+        let mut id_col = vec![0f64; 10];
+        id_col[i] = 1f64;
+    }
+
+    for _v in vec.iter() {}
+
+    for _v in vec.iter_mut() {}
+
+    let out_vec = vec![1, 2, 3];
+    for _v in out_vec.into_iter() {}
+
+    for _v in &vec {} // these are fine
+    for _v in &mut vec {} // these are fine
+
+    for _v in [1, 2, 3].iter() {}
+
+    for _v in (&mut [1, 2, 3]).iter() {} // no error
+
+    for _v in [0; 32].iter() {}
+
+    for _v in [0; 33].iter() {} // no error
+
+    let ll: LinkedList<()> = LinkedList::new();
+    for _v in ll.iter() {}
+
+    let vd: VecDeque<()> = VecDeque::new();
+    for _v in vd.iter() {}
+
+    let bh: BinaryHeap<()> = BinaryHeap::new();
+    for _v in bh.iter() {}
+
+    let hm: HashMap<(), ()> = HashMap::new();
+    for _v in hm.iter() {}
+
+    let bt: BTreeMap<(), ()> = BTreeMap::new();
+    for _v in bt.iter() {}
+
+    let hs: HashSet<()> = HashSet::new();
+    for _v in hs.iter() {}
+
+    let bs: BTreeSet<()> = BTreeSet::new();
+    for _v in bs.iter() {}
+
+    let u = Unrelated(vec![]);
+    for _v in u.next() {} // no error
+    for _v in u.iter() {} // no error
+
+    let mut out = vec![];
+    vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
+    let _y = vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine
+
+    // Loop with explicit counter variable
+
+    // Potential false positives
+    let mut _index = 0;
+    _index = 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    _index += 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    if true {
+        _index = 1
+    }
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    let mut _index = 1;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index *= 2;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index = 1;
+        _index += 1
+    }
+
+    let mut _index = 0;
+
+    for _v in &vec {
+        let mut _index = 0;
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1;
+        _index = 0;
+    }
+
+    let mut _index = 0;
+    for _v in &vec {
+        for _x in 0..1 {
+            _index += 1;
+        }
+        _index += 1
+    }
+
+    let mut _index = 0;
+    for x in &vec {
+        if *x == 1 {
+            _index += 1
+        }
+    }
+
+    let mut _index = 0;
+    if true {
+        _index = 1
+    };
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 1;
+    if false {
+        _index = 0
+    };
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut index = 0;
+    {
+        let mut _x = &mut index;
+    }
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut index = 0;
+    for _v in &vec {
+        index += 1
+    }
+    println!("index: {}", index);
+
+    fn f<T>(_: &T, _: &T) -> bool {
+        unimplemented!()
+    }
+    fn g<T>(_: &mut [T], _: usize, _: usize) {
+        unimplemented!()
+    }
+    for i in 1..vec.len() {
+        if f(&vec[i - 1], &vec[i]) {
+            g(&mut vec, i - 1, i);
+        }
+    }
+
+    for mid in 1..vec.len() {
+        let (_, _) = vec.split_at(mid);
+    }
+}
+
+fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
+    let pivot = v.len() - 1;
+    let mut i = 0;
+    for j in 0..pivot {
+        if v[j] <= v[pivot] {
+            v.swap(i, j);
+            i += 1;
+        }
+    }
+    v.swap(i, pivot);
+    i
+}
+
+#[warn(clippy::needless_range_loop)]
+pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) {
+    // Same source and destination - don't trigger lint
+    for i in 0..dst.len() {
+        dst[d + i] = dst[s + i];
+    }
+}
+
+mod issue_2496 {
+    pub trait Handle {
+        fn new_for_index(index: usize) -> Self;
+        fn index(&self) -> usize;
+    }
+
+    pub fn test<H: Handle>() -> H {
+        for x in 0..5 {
+            let next_handle = H::new_for_index(x);
+            println!("{}", next_handle.index());
+        }
+        unimplemented!()
+    }
+}
+
+// explicit_into_iter_loop bad suggestions
+#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)]
+mod issue_4958 {
+    fn takes_iterator<T>(iterator: &T)
+    where
+        for<'a> &'a T: IntoIterator<Item = &'a String>,
+    {
+        for i in iterator.into_iter() {
+            println!("{}", i);
+        }
+    }
+
+    struct T;
+    impl IntoIterator for &T {
+        type Item = ();
+        type IntoIter = std::vec::IntoIter<Self::Item>;
+        fn into_iter(self) -> Self::IntoIter {
+            vec![].into_iter()
+        }
+    }
+
+    fn more_tests() {
+        let t = T;
+        let r = &t;
+        let rr = &&t;
+
+        // This case is handled by `explicit_iter_loop`. No idea why.
+        for _ in t.into_iter() {}
+
+        for _ in r.into_iter() {}
+
+        // No suggestion for this.
+        // We'd have to suggest `for _ in *rr {}` which is less clear.
+        for _ in rr.into_iter() {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.stderr b/src/tools/clippy/tests/ui/for_loop_fixable.stderr
new file mode 100644
index 00000000000..cffb4b9f0a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.stderr
@@ -0,0 +1,152 @@
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop_fixable.rs:38:14
+   |
+LL |     for i in 10..0 {
+   |              ^^^^^
+   |
+   = note: `-D clippy::reverse-range-loop` implied by `-D warnings`
+help: consider using the following if you are attempting to iterate over this range in reverse
+   |
+LL |     for i in (0..10).rev() {
+   |              ^^^^^^^^^^^^^
+
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop_fixable.rs:42:14
+   |
+LL |     for i in 10..=0 {
+   |              ^^^^^^
+   |
+help: consider using the following if you are attempting to iterate over this range in reverse
+   |
+LL |     for i in (0..=10).rev() {
+   |              ^^^^^^^^^^^^^^
+
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop_fixable.rs:46:14
+   |
+LL |     for i in MAX_LEN..0 {
+   |              ^^^^^^^^^^
+   |
+help: consider using the following if you are attempting to iterate over this range in reverse
+   |
+LL |     for i in (0..MAX_LEN).rev() {
+   |              ^^^^^^^^^^^^^^^^^^
+
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop_fixable.rs:71:14
+   |
+LL |     for i in 10..5 + 4 {
+   |              ^^^^^^^^^
+   |
+help: consider using the following if you are attempting to iterate over this range in reverse
+   |
+LL |     for i in (5 + 4..10).rev() {
+   |              ^^^^^^^^^^^^^^^^^
+
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop_fixable.rs:75:14
+   |
+LL |     for i in (5 + 2)..(3 - 1) {
+   |              ^^^^^^^^^^^^^^^^
+   |
+help: consider using the following if you are attempting to iterate over this range in reverse
+   |
+LL |     for i in ((3 - 1)..(5 + 2)).rev() {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:97:15
+   |
+LL |     for _v in vec.iter() {}
+   |               ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
+   |
+   = note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:99:15
+   |
+LL |     for _v in vec.iter_mut() {}
+   |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
+
+error: it is more concise to loop over containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:102:15
+   |
+LL |     for _v in out_vec.into_iter() {}
+   |               ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
+   |
+   = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:107:15
+   |
+LL |     for _v in [1, 2, 3].iter() {}
+   |               ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:111:15
+   |
+LL |     for _v in [0; 32].iter() {}
+   |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:116:15
+   |
+LL |     for _v in ll.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&ll`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:119:15
+   |
+LL |     for _v in vd.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&vd`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:122:15
+   |
+LL |     for _v in bh.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&bh`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:125:15
+   |
+LL |     for _v in hm.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&hm`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:128:15
+   |
+LL |     for _v in bt.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&bt`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:131:15
+   |
+LL |     for _v in hs.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&hs`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:134:15
+   |
+LL |     for _v in bs.iter() {}
+   |               ^^^^^^^^^ help: to write this more concisely, try: `&bs`
+
+error: it is more concise to loop over containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:309:18
+   |
+LL |         for i in iterator.into_iter() {
+   |                  ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:329:18
+   |
+LL |         for _ in t.into_iter() {}
+   |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t`
+
+error: it is more concise to loop over containers instead of using explicit iteration methods
+  --> $DIR/for_loop_fixable.rs:331:18
+   |
+LL |         for _ in r.into_iter() {}
+   |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `r`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/for_loop_over_option_result.rs b/src/tools/clippy/tests/ui/for_loop_over_option_result.rs
new file mode 100644
index 00000000000..6b207b26b6b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_over_option_result.rs
@@ -0,0 +1,59 @@
+#![warn(clippy::for_loop_over_option, clippy::for_loop_over_result)]
+
+/// Tests for_loop_over_result and for_loop_over_option
+
+fn for_loop_over_option_and_result() {
+    let option = Some(1);
+    let result = option.ok_or("x not found");
+    let v = vec![0, 1, 2];
+
+    // check FOR_LOOP_OVER_OPTION lint
+    for x in option {
+        println!("{}", x);
+    }
+
+    // check FOR_LOOP_OVER_RESULT lint
+    for x in result {
+        println!("{}", x);
+    }
+
+    for x in option.ok_or("x not found") {
+        println!("{}", x);
+    }
+
+    // make sure LOOP_OVER_NEXT lint takes clippy::precedence when next() is the last call
+    // in the chain
+    for x in v.iter().next() {
+        println!("{}", x);
+    }
+
+    // make sure we lint when next() is not the last call in the chain
+    for x in v.iter().next().and(Some(0)) {
+        println!("{}", x);
+    }
+
+    for x in v.iter().next().ok_or("x not found") {
+        println!("{}", x);
+    }
+
+    // check for false positives
+
+    // for loop false positive
+    for x in v {
+        println!("{}", x);
+    }
+
+    // while let false positive for Option
+    while let Some(x) = option {
+        println!("{}", x);
+        break;
+    }
+
+    // while let false positive for Result
+    while let Ok(x) = result {
+        println!("{}", x);
+        break;
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/for_loop_over_option_result.stderr b/src/tools/clippy/tests/ui/for_loop_over_option_result.stderr
new file mode 100644
index 00000000000..194a0bfec5b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_over_option_result.stderr
@@ -0,0 +1,72 @@
+error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:11:14
+   |
+LL |     for x in option {
+   |              ^^^^^^
+   |
+   = note: `-D clippy::for-loop-over-option` implied by `-D warnings`
+   = help: consider replacing `for x in option` with `if let Some(x) = option`
+
+error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:16:14
+   |
+LL |     for x in result {
+   |              ^^^^^^
+   |
+   = note: `-D clippy::for-loop-over-result` implied by `-D warnings`
+   = help: consider replacing `for x in result` with `if let Ok(x) = result`
+
+error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:20:14
+   |
+LL |     for x in option.ok_or("x not found") {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
+
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
+  --> $DIR/for_loop_over_option_result.rs:26:14
+   |
+LL |     for x in v.iter().next() {
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::iter_next_loop)]` on by default
+
+error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:31:14
+   |
+LL |     for x in v.iter().next().and(Some(0)) {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
+
+error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:35:14
+   |
+LL |     for x in v.iter().next().ok_or("x not found") {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
+
+error: this loop never actually loops
+  --> $DIR/for_loop_over_option_result.rs:47:5
+   |
+LL | /     while let Some(x) = option {
+LL | |         println!("{}", x);
+LL | |         break;
+LL | |     }
+   | |_____^
+   |
+   = note: `#[deny(clippy::never_loop)]` on by default
+
+error: this loop never actually loops
+  --> $DIR/for_loop_over_option_result.rs:53:5
+   |
+LL | /     while let Ok(x) = result {
+LL | |         println!("{}", x);
+LL | |         break;
+LL | |     }
+   | |_____^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.rs b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
new file mode 100644
index 00000000000..179b255e08c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
@@ -0,0 +1,40 @@
+// Tests from for_loop.rs that don't have suggestions
+
+#[warn(
+    clippy::needless_range_loop,
+    clippy::explicit_iter_loop,
+    clippy::explicit_into_iter_loop,
+    clippy::iter_next_loop,
+    clippy::reverse_range_loop,
+    clippy::for_kv_map
+)]
+#[allow(
+    clippy::linkedlist,
+    clippy::shadow_unrelated,
+    clippy::unnecessary_mut_passed,
+    clippy::similar_names,
+    unused,
+    dead_code
+)]
+#[allow(clippy::many_single_char_names, unused_variables)]
+fn main() {
+    for i in 5..5 {
+        println!("{}", i);
+    }
+
+    let vec = vec![1, 2, 3, 4];
+
+    for _v in vec.iter().next() {}
+
+    for i in (5 + 2)..(8 - 1) {
+        println!("{}", i);
+    }
+
+    const ZERO: usize = 0;
+
+    for i in ZERO..vec.len() {
+        if f(&vec[i], &vec[i]) {
+            panic!("at the disco");
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.stderr b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
new file mode 100644
index 00000000000..1da8e0f3588
--- /dev/null
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find function `f` in this scope
+  --> $DIR/for_loop_unfixable.rs:36:12
+   |
+LL |         if f(&vec[i], &vec[i]) {
+   |            ^ help: a local variable with a similar name exists: `i`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/tools/clippy/tests/ui/forget_ref.rs b/src/tools/clippy/tests/ui/forget_ref.rs
new file mode 100644
index 00000000000..447fdbe1fac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/forget_ref.rs
@@ -0,0 +1,48 @@
+#![warn(clippy::forget_ref)]
+#![allow(clippy::toplevel_ref_arg)]
+
+use std::mem::forget;
+
+struct SomeStruct;
+
+fn main() {
+    forget(&SomeStruct);
+
+    let mut owned = SomeStruct;
+    forget(&owned);
+    forget(&&owned);
+    forget(&mut owned);
+    forget(owned); //OK
+
+    let reference1 = &SomeStruct;
+    forget(&*reference1);
+
+    let reference2 = &mut SomeStruct;
+    forget(reference2);
+
+    let ref reference3 = SomeStruct;
+    forget(reference3);
+}
+
+#[allow(dead_code)]
+fn test_generic_fn_forget<T>(val: T) {
+    forget(&val);
+    forget(val); //OK
+}
+
+#[allow(dead_code)]
+fn test_similarly_named_function() {
+    fn forget<T>(_val: T) {}
+    forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name
+    std::mem::forget(&SomeStruct);
+}
+
+#[derive(Copy, Clone)]
+pub struct Error;
+fn produce_half_owl_error() -> Result<(), Error> {
+    Ok(())
+}
+
+fn produce_half_owl_ok() -> Result<bool, ()> {
+    Ok(true)
+}
diff --git a/src/tools/clippy/tests/ui/forget_ref.stderr b/src/tools/clippy/tests/ui/forget_ref.stderr
new file mode 100644
index 00000000000..f90bcc2762c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/forget_ref.stderr
@@ -0,0 +1,111 @@
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:9:5
+   |
+LL |     forget(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::forget-ref` implied by `-D warnings`
+note: argument has type `&SomeStruct`
+  --> $DIR/forget_ref.rs:9:12
+   |
+LL |     forget(&SomeStruct);
+   |            ^^^^^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:12:5
+   |
+LL |     forget(&owned);
+   |     ^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/forget_ref.rs:12:12
+   |
+LL |     forget(&owned);
+   |            ^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:13:5
+   |
+LL |     forget(&&owned);
+   |     ^^^^^^^^^^^^^^^
+   |
+note: argument has type `&&SomeStruct`
+  --> $DIR/forget_ref.rs:13:12
+   |
+LL |     forget(&&owned);
+   |            ^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:14:5
+   |
+LL |     forget(&mut owned);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&mut SomeStruct`
+  --> $DIR/forget_ref.rs:14:12
+   |
+LL |     forget(&mut owned);
+   |            ^^^^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:18:5
+   |
+LL |     forget(&*reference1);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/forget_ref.rs:18:12
+   |
+LL |     forget(&*reference1);
+   |            ^^^^^^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:21:5
+   |
+LL |     forget(reference2);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&mut SomeStruct`
+  --> $DIR/forget_ref.rs:21:12
+   |
+LL |     forget(reference2);
+   |            ^^^^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:24:5
+   |
+LL |     forget(reference3);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/forget_ref.rs:24:12
+   |
+LL |     forget(reference3);
+   |            ^^^^^^^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:29:5
+   |
+LL |     forget(&val);
+   |     ^^^^^^^^^^^^
+   |
+note: argument has type `&T`
+  --> $DIR/forget_ref.rs:29:12
+   |
+LL |     forget(&val);
+   |            ^^^^
+
+error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+  --> $DIR/forget_ref.rs:37:5
+   |
+LL |     std::mem::forget(&SomeStruct);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: argument has type `&SomeStruct`
+  --> $DIR/forget_ref.rs:37:22
+   |
+LL |     std::mem::forget(&SomeStruct);
+   |                      ^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
new file mode 100644
index 00000000000..30651476999
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -0,0 +1,67 @@
+// run-rustfix
+
+#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![warn(clippy::useless_format)]
+
+struct Foo(pub String);
+
+macro_rules! foo {
+    ($($t:tt)*) => (Foo(format!($($t)*)))
+}
+
+fn main() {
+    "foo".to_string();
+    "{}".to_string();
+    "{} abc {}".to_string();
+    "foo {}\n\" bar".to_string();
+
+    "foo".to_string();
+    format!("{:?}", "foo"); // Don't warn about `Debug`.
+    format!("{:8}", "foo");
+    format!("{:width$}", "foo", width = 8);
+    "foo".to_string(); // Warn when the format makes no difference.
+    "foo".to_string(); // Warn when the format makes no difference.
+    format!("foo {}", "bar");
+    format!("{} bar", "foo");
+
+    let arg: String = "".to_owned();
+    arg.to_string();
+    format!("{:?}", arg); // Don't warn about debug.
+    format!("{:8}", arg);
+    format!("{:width$}", arg, width = 8);
+    arg.to_string(); // Warn when the format makes no difference.
+    arg.to_string(); // Warn when the format makes no difference.
+    format!("foo {}", arg);
+    format!("{} bar", arg);
+
+    // We don’t want to warn for non-string args; see issue #697.
+    format!("{}", 42);
+    format!("{:?}", 42);
+    format!("{:+}", 42);
+    format!("foo {}", 42);
+    format!("{} bar", 42);
+
+    // We only want to warn about `format!` itself.
+    println!("foo");
+    println!("{}", "foo");
+    println!("foo {}", "foo");
+    println!("{}", 42);
+    println!("foo {}", 42);
+
+    // A `format!` inside a macro should not trigger a warning.
+    foo!("should not warn");
+
+    // Precision on string means slicing without panicking on size.
+    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
+    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
+    format!("{:.prec$}", "foo", prec = 1);
+    format!("{:.prec$}", "foo", prec = 10);
+
+    42.to_string();
+    let x = std::path::PathBuf::from("/bar/foo/qux");
+    x.display().to_string();
+
+    // False positive
+    let a = "foo".to_string();
+    let _ = Some(a + "bar");
+}
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
new file mode 100644
index 00000000000..b604d79cca3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -0,0 +1,70 @@
+// run-rustfix
+
+#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![warn(clippy::useless_format)]
+
+struct Foo(pub String);
+
+macro_rules! foo {
+    ($($t:tt)*) => (Foo(format!($($t)*)))
+}
+
+fn main() {
+    format!("foo");
+    format!("{{}}");
+    format!("{{}} abc {{}}");
+    format!(
+        r##"foo {{}}
+" bar"##
+    );
+
+    format!("{}", "foo");
+    format!("{:?}", "foo"); // Don't warn about `Debug`.
+    format!("{:8}", "foo");
+    format!("{:width$}", "foo", width = 8);
+    format!("{:+}", "foo"); // Warn when the format makes no difference.
+    format!("{:<}", "foo"); // Warn when the format makes no difference.
+    format!("foo {}", "bar");
+    format!("{} bar", "foo");
+
+    let arg: String = "".to_owned();
+    format!("{}", arg);
+    format!("{:?}", arg); // Don't warn about debug.
+    format!("{:8}", arg);
+    format!("{:width$}", arg, width = 8);
+    format!("{:+}", arg); // Warn when the format makes no difference.
+    format!("{:<}", arg); // Warn when the format makes no difference.
+    format!("foo {}", arg);
+    format!("{} bar", arg);
+
+    // We don’t want to warn for non-string args; see issue #697.
+    format!("{}", 42);
+    format!("{:?}", 42);
+    format!("{:+}", 42);
+    format!("foo {}", 42);
+    format!("{} bar", 42);
+
+    // We only want to warn about `format!` itself.
+    println!("foo");
+    println!("{}", "foo");
+    println!("foo {}", "foo");
+    println!("{}", 42);
+    println!("foo {}", 42);
+
+    // A `format!` inside a macro should not trigger a warning.
+    foo!("should not warn");
+
+    // Precision on string means slicing without panicking on size.
+    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
+    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
+    format!("{:.prec$}", "foo", prec = 1);
+    format!("{:.prec$}", "foo", prec = 10);
+
+    format!("{}", 42.to_string());
+    let x = std::path::PathBuf::from("/bar/foo/qux");
+    format!("{}", x.display().to_string());
+
+    // False positive
+    let a = "foo".to_string();
+    let _ = Some(format!("{}", a + "bar"));
+}
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
new file mode 100644
index 00000000000..9734492154e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -0,0 +1,85 @@
+error: useless use of `format!`
+  --> $DIR/format.rs:13:5
+   |
+LL |     format!("foo");
+   |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();`
+   |
+   = note: `-D clippy::useless-format` implied by `-D warnings`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:14:5
+   |
+LL |     format!("{{}}");
+   |     ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:15:5
+   |
+LL |     format!("{{}} abc {{}}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:16:5
+   |
+LL | /     format!(
+LL | |         r##"foo {{}}
+LL | | " bar"##
+LL | |     );
+   | |______^ help: consider using `.to_string()`: `"foo {}/n/" bar".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:21:5
+   |
+LL |     format!("{}", "foo");
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:25:5
+   |
+LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:26:5
+   |
+LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:31:5
+   |
+LL |     format!("{}", arg);
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:35:5
+   |
+LL |     format!("{:+}", arg); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:36:5
+   |
+LL |     format!("{:<}", arg); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:63:5
+   |
+LL |     format!("{}", 42.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:65:5
+   |
+LL |     format!("{}", x.display().to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:69:18
+   |
+LL |     let _ = Some(format!("{}", a + "bar"));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/formatting.rs b/src/tools/clippy/tests/ui/formatting.rs
new file mode 100644
index 00000000000..078811b8d88
--- /dev/null
+++ b/src/tools/clippy/tests/ui/formatting.rs
@@ -0,0 +1,157 @@
+#![warn(clippy::all)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+#![allow(clippy::if_same_then_else)]
+#![allow(clippy::deref_addrof)]
+
+fn foo() -> bool {
+    true
+}
+
+#[rustfmt::skip]
+fn main() {
+    // weird `else` formatting:
+    if foo() {
+    } {
+    }
+
+    if foo() {
+    } if foo() {
+    }
+
+    let _ = { // if as the last expression
+        let _ = 0;
+
+        if foo() {
+        } if foo() {
+        }
+        else {
+        }
+    };
+
+    let _ = { // if in the middle of a block
+        if foo() {
+        } if foo() {
+        }
+        else {
+        }
+
+        let _ = 0;
+    };
+
+    if foo() {
+    } else
+    {
+    }
+
+    if foo() {
+    }
+    else
+    {
+    }
+
+    if foo() {
+    } else
+    if foo() { // the span of the above error should continue here
+    }
+
+    if foo() {
+    }
+    else
+    if foo() { // the span of the above error should continue here
+    }
+
+    // those are ok:
+    if foo() {
+    }
+    {
+    }
+
+    if foo() {
+    } else {
+    }
+
+    if foo() {
+    }
+    else {
+    }
+
+    if foo() {
+    }
+    if foo() {
+    }
+
+    if foo() {
+    } else if foo() {
+    }
+
+    if foo() {
+    }
+    else if foo() {
+    }
+
+    if foo() {
+    }
+    else if
+    foo() {}
+
+    // weird op_eq formatting:
+    let mut a = 42;
+    a =- 35;
+    a =* &191;
+
+    let mut b = true;
+    b =! false;
+
+    // those are ok:
+    a = -35;
+    a = *&191;
+    b = !false;
+
+    // possible missing comma in an array
+    let _ = &[
+        -1, -2, -3 // <= no comma here
+        -4, -5, -6
+    ];
+    let _ = &[
+        -1, -2, -3 // <= no comma here
+        *4, -5, -6
+    ];
+
+    // those are ok:
+    let _ = &[
+        -1, -2, -3,
+        -4, -5, -6
+    ];
+    let _ = &[
+        -1, -2, -3,
+        -4, -5, -6,
+    ];
+    let _ = &[
+        1 + 2, 3 +
+        4, 5 + 6,
+    ];
+
+    // don't lint for bin op without unary equiv
+    // issue 3244
+    vec![
+        1
+        / 2,
+    ];
+    // issue 3396
+    vec![
+        true
+        | false,
+    ];
+
+    // don't lint if the indentation suggests not to
+    let _ = &[
+        1 + 2, 3 
+                - 4, 5
+    ];
+    // lint if it doesnt
+    let _ = &[
+        -1
+        -4,
+    ];
+}
diff --git a/src/tools/clippy/tests/ui/formatting.stderr b/src/tools/clippy/tests/ui/formatting.stderr
new file mode 100644
index 00000000000..e2095cc125b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/formatting.stderr
@@ -0,0 +1,127 @@
+error: this looks like an `else {..}` but the `else` is missing
+  --> $DIR/formatting.rs:15:6
+   |
+LL |     } {
+   |      ^
+   |
+   = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
+   = note: to remove this lint, add the missing `else` or add a new line before the next block
+
+error: this looks like an `else if` but the `else` is missing
+  --> $DIR/formatting.rs:19:6
+   |
+LL |     } if foo() {
+   |      ^
+   |
+   = note: to remove this lint, add the missing `else` or add a new line before the second `if`
+
+error: this looks like an `else if` but the `else` is missing
+  --> $DIR/formatting.rs:26:10
+   |
+LL |         } if foo() {
+   |          ^
+   |
+   = note: to remove this lint, add the missing `else` or add a new line before the second `if`
+
+error: this looks like an `else if` but the `else` is missing
+  --> $DIR/formatting.rs:34:10
+   |
+LL |         } if foo() {
+   |          ^
+   |
+   = note: to remove this lint, add the missing `else` or add a new line before the second `if`
+
+error: this is an `else {..}` but the formatting might hide it
+  --> $DIR/formatting.rs:43:6
+   |
+LL |       } else
+   |  ______^
+LL | |     {
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+  --> $DIR/formatting.rs:48:6
+   |
+LL |       }
+   |  ______^
+LL | |     else
+LL | |     {
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else if` but the formatting might hide it
+  --> $DIR/formatting.rs:54:6
+   |
+LL |       } else
+   |  ______^
+LL | |     if foo() { // the span of the above error should continue here
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
+
+error: this is an `else if` but the formatting might hide it
+  --> $DIR/formatting.rs:59:6
+   |
+LL |       }
+   |  ______^
+LL | |     else
+LL | |     if foo() { // the span of the above error should continue here
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
+
+error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
+  --> $DIR/formatting.rs:100:6
+   |
+LL |     a =- 35;
+   |      ^^^^
+   |
+   = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
+   = note: to remove this lint, use either `-=` or `= -`
+
+error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
+  --> $DIR/formatting.rs:101:6
+   |
+LL |     a =* &191;
+   |      ^^^^
+   |
+   = note: to remove this lint, use either `*=` or `= *`
+
+error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
+  --> $DIR/formatting.rs:104:6
+   |
+LL |     b =! false;
+   |      ^^^^
+   |
+   = note: to remove this lint, use either `!=` or `= !`
+
+error: possibly missing a comma here
+  --> $DIR/formatting.rs:113:19
+   |
+LL |         -1, -2, -3 // <= no comma here
+   |                   ^
+   |
+   = note: `-D clippy::possible-missing-comma` implied by `-D warnings`
+   = note: to remove this lint, add a comma or write the expr in a single line
+
+error: possibly missing a comma here
+  --> $DIR/formatting.rs:117:19
+   |
+LL |         -1, -2, -3 // <= no comma here
+   |                   ^
+   |
+   = note: to remove this lint, add a comma or write the expr in a single line
+
+error: possibly missing a comma here
+  --> $DIR/formatting.rs:154:11
+   |
+LL |         -1
+   |           ^
+   |
+   = note: to remove this lint, add a comma or write the expr in a single line
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/functions.rs b/src/tools/clippy/tests/ui/functions.rs
new file mode 100644
index 00000000000..271754cb06e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/functions.rs
@@ -0,0 +1,104 @@
+#![warn(clippy::all)]
+#![allow(dead_code)]
+#![allow(unused_unsafe, clippy::missing_safety_doc)]
+
+// TOO_MANY_ARGUMENTS
+fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {}
+
+fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+
+#[rustfmt::skip]
+fn bad_multiline(
+    one: u32,
+    two: u32,
+    three: &str,
+    four: bool,
+    five: f32,
+    six: f32,
+    seven: bool,
+    eight: ()
+) {
+    let _one = one;
+    let _two = two;
+    let _three = three;
+    let _four = four;
+    let _five = five;
+    let _six = six;
+    let _seven = seven;
+}
+
+// don't lint extern fns
+extern "C" fn extern_fn(
+    _one: u32,
+    _two: u32,
+    _three: *const u8,
+    _four: bool,
+    _five: f32,
+    _six: f32,
+    _seven: bool,
+    _eight: *const std::ffi::c_void,
+) {
+}
+
+pub trait Foo {
+    fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool);
+    fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
+
+    fn ptr(p: *const u8);
+}
+
+pub struct Bar;
+
+impl Bar {
+    fn good_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {}
+    fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+}
+
+// ok, we don’t want to warn implementations
+impl Foo for Bar {
+    fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {}
+    fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+
+    fn ptr(p: *const u8) {
+        println!("{}", unsafe { *p });
+        println!("{:?}", unsafe { p.as_ref() });
+        unsafe { std::ptr::read(p) };
+    }
+}
+
+// NOT_UNSAFE_PTR_ARG_DEREF
+
+fn private(p: *const u8) {
+    println!("{}", unsafe { *p });
+}
+
+pub fn public(p: *const u8) {
+    println!("{}", unsafe { *p });
+    println!("{:?}", unsafe { p.as_ref() });
+    unsafe { std::ptr::read(p) };
+}
+
+impl Bar {
+    fn private(self, p: *const u8) {
+        println!("{}", unsafe { *p });
+    }
+
+    pub fn public(self, p: *const u8) {
+        println!("{}", unsafe { *p });
+        println!("{:?}", unsafe { p.as_ref() });
+        unsafe { std::ptr::read(p) };
+    }
+
+    pub fn public_ok(self, p: *const u8) {
+        if !p.is_null() {
+            println!("{:p}", p);
+        }
+    }
+
+    pub unsafe fn public_unsafe(self, p: *const u8) {
+        println!("{}", unsafe { *p });
+        println!("{:?}", unsafe { p.as_ref() });
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
new file mode 100644
index 00000000000..0a86568b18d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -0,0 +1,90 @@
+error: this function has too many arguments (8/7)
+  --> $DIR/functions.rs:8:1
+   |
+LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::too-many-arguments` implied by `-D warnings`
+
+error: this function has too many arguments (8/7)
+  --> $DIR/functions.rs:11:1
+   |
+LL | / fn bad_multiline(
+LL | |     one: u32,
+LL | |     two: u32,
+LL | |     three: &str,
+...  |
+LL | |     eight: ()
+LL | | ) {
+   | |__^
+
+error: this function has too many arguments (8/7)
+  --> $DIR/functions.rs:45:5
+   |
+LL |     fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function has too many arguments (8/7)
+  --> $DIR/functions.rs:54:5
+   |
+LL |     fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:63:34
+   |
+LL |         println!("{}", unsafe { *p });
+   |                                  ^
+   |
+   = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:64:35
+   |
+LL |         println!("{:?}", unsafe { p.as_ref() });
+   |                                   ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:65:33
+   |
+LL |         unsafe { std::ptr::read(p) };
+   |                                 ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:76:30
+   |
+LL |     println!("{}", unsafe { *p });
+   |                              ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:77:31
+   |
+LL |     println!("{:?}", unsafe { p.as_ref() });
+   |                               ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:78:29
+   |
+LL |     unsafe { std::ptr::read(p) };
+   |                             ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:87:34
+   |
+LL |         println!("{}", unsafe { *p });
+   |                                  ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:88:35
+   |
+LL |         println!("{:?}", unsafe { p.as_ref() });
+   |                                   ^
+
+error: this public function dereferences a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:89:33
+   |
+LL |         unsafe { std::ptr::read(p) };
+   |                                 ^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/functions_maxlines.rs b/src/tools/clippy/tests/ui/functions_maxlines.rs
new file mode 100644
index 00000000000..5e1ee55e010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/functions_maxlines.rs
@@ -0,0 +1,163 @@
+#![warn(clippy::too_many_lines)]
+
+fn good_lines() {
+    /* println!("This is good."); */
+    // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good."); */
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+}
+
+fn bad_lines() {
+    println!("Dont get confused by braces: {{}}");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr
new file mode 100644
index 00000000000..9b0e7550cc3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr
@@ -0,0 +1,16 @@
+error: This function has a large number of lines.
+  --> $DIR/functions_maxlines.rs:58:1
+   |
+LL | / fn bad_lines() {
+LL | |     println!("Dont get confused by braces: {{}}");
+LL | |     println!("This is bad.");
+LL | |     println!("This is bad.");
+...  |
+LL | |     println!("This is bad.");
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::too-many-lines` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/future_not_send.rs b/src/tools/clippy/tests/ui/future_not_send.rs
new file mode 100644
index 00000000000..6d09d71a630
--- /dev/null
+++ b/src/tools/clippy/tests/ui/future_not_send.rs
@@ -0,0 +1,79 @@
+// edition:2018
+#![warn(clippy::future_not_send)]
+
+use std::cell::Cell;
+use std::rc::Rc;
+use std::sync::Arc;
+
+async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+    async { true }.await
+}
+
+pub async fn public_future(rc: Rc<[u8]>) {
+    async { true }.await;
+}
+
+pub async fn public_send(arc: Arc<[u8]>) -> bool {
+    async { false }.await
+}
+
+async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+    true
+}
+
+pub async fn public_future2(rc: Rc<[u8]>) {}
+
+pub async fn public_send2(arc: Arc<[u8]>) -> bool {
+    false
+}
+
+struct Dummy {
+    rc: Rc<[u8]>,
+}
+
+impl Dummy {
+    async fn private_future(&self) -> usize {
+        async { true }.await;
+        self.rc.len()
+    }
+
+    pub async fn public_future(&self) {
+        self.private_future().await;
+    }
+
+    pub fn public_send(&self) -> impl std::future::Future<Output = bool> {
+        async { false }
+    }
+}
+
+async fn generic_future<T>(t: T) -> T
+where
+    T: Send,
+{
+    let rt = &t;
+    async { true }.await;
+    t
+}
+
+async fn generic_future_send<T>(t: T)
+where
+    T: Send,
+{
+    async { true }.await;
+}
+
+async fn unclear_future<T>(t: T) {}
+
+fn main() {
+    let rc = Rc::new([1, 2, 3]);
+    private_future(rc.clone(), &Cell::new(42));
+    public_future(rc.clone());
+    let arc = Arc::new([4, 5, 6]);
+    public_send(arc);
+    generic_future(42);
+    generic_future_send(42);
+
+    let dummy = Dummy { rc };
+    dummy.public_future();
+    dummy.public_send();
+}
diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
new file mode 100644
index 00000000000..3b4968ef0a6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -0,0 +1,125 @@
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:8:62
+   |
+LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+   |                                                              ^^^^ future returned by `private_future` is not `Send`
+   |
+   = note: `-D clippy::future-not-send` implied by `-D warnings`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:9:5
+   |
+LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+   |                         -- has type `std::rc::Rc<[u8]>` which is not `Send`
+LL |     async { true }.await
+   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
+LL | }
+   | - `rc` is later dropped here
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:9:5
+   |
+LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+   |                                       ---- has type `&std::cell::Cell<usize>` which is not `Send`
+LL |     async { true }.await
+   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later
+LL | }
+   | - `cell` is later dropped here
+   = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:12:42
+   |
+LL | pub async fn public_future(rc: Rc<[u8]>) {
+   |                                          ^ future returned by `public_future` is not `Send`
+   |
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:13:5
+   |
+LL | pub async fn public_future(rc: Rc<[u8]>) {
+   |                            -- has type `std::rc::Rc<[u8]>` which is not `Send`
+LL |     async { true }.await;
+   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
+LL | }
+   | - `rc` is later dropped here
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:20:63
+   |
+LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
+   |                                                               ^^^^
+   |
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
+   = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:24:43
+   |
+LL | pub async fn public_future2(rc: Rc<[u8]>) {}
+   |                                           ^
+   |
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:35:39
+   |
+LL |     async fn private_future(&self) -> usize {
+   |                                       ^^^^^ future returned by `private_future` is not `Send`
+   |
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:36:9
+   |
+LL |     async fn private_future(&self) -> usize {
+   |                             ----- has type `&Dummy` which is not `Send`
+LL |         async { true }.await;
+   |         ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
+LL |         self.rc.len()
+LL |     }
+   |     - `&self` is later dropped here
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:40:39
+   |
+LL |     pub async fn public_future(&self) {
+   |                                       ^ future returned by `public_future` is not `Send`
+   |
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:41:9
+   |
+LL |     pub async fn public_future(&self) {
+   |                                ----- has type `&Dummy` which is not `Send`
+LL |         self.private_future().await;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
+LL |     }
+   |     - `&self` is later dropped here
+   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:49:37
+   |
+LL | async fn generic_future<T>(t: T) -> T
+   |                                     ^ future returned by `generic_future` is not `Send`
+   |
+note: future is not `Send` as this value is used across an await
+  --> $DIR/future_not_send.rs:54:5
+   |
+LL |     let rt = &t;
+   |         -- has type `&T` which is not `Send`
+LL |     async { true }.await;
+   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later
+LL |     t
+LL | }
+   | - `rt` is later dropped here
+   = note: `T` doesn't implement `std::marker::Sync`
+
+error: future cannot be sent between threads safely
+  --> $DIR/future_not_send.rs:65:34
+   |
+LL | async fn unclear_future<T>(t: T) {}
+   |                                  ^
+   |
+   = note: `T` doesn't implement `std::marker::Send`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/get_last_with_len.fixed b/src/tools/clippy/tests/ui/get_last_with_len.fixed
new file mode 100644
index 00000000000..c8b363f9c38
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_last_with_len.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![warn(clippy::get_last_with_len)]
+
+fn dont_use_last() {
+    let x = vec![2, 3, 5];
+    let _ = x.last(); // ~ERROR Use x.last()
+}
+
+fn indexing_two_from_end() {
+    let x = vec![2, 3, 5];
+    let _ = x.get(x.len() - 2);
+}
+
+fn index_into_last() {
+    let x = vec![2, 3, 5];
+    let _ = x[x.len() - 1];
+}
+
+fn use_last_with_different_vec_length() {
+    let x = vec![2, 3, 5];
+    let y = vec!['a', 'b', 'c'];
+    let _ = x.get(y.len() - 1);
+}
+
+fn main() {
+    dont_use_last();
+    indexing_two_from_end();
+    index_into_last();
+    use_last_with_different_vec_length();
+}
diff --git a/src/tools/clippy/tests/ui/get_last_with_len.rs b/src/tools/clippy/tests/ui/get_last_with_len.rs
new file mode 100644
index 00000000000..bf9cb2d7e0c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_last_with_len.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![warn(clippy::get_last_with_len)]
+
+fn dont_use_last() {
+    let x = vec![2, 3, 5];
+    let _ = x.get(x.len() - 1); // ~ERROR Use x.last()
+}
+
+fn indexing_two_from_end() {
+    let x = vec![2, 3, 5];
+    let _ = x.get(x.len() - 2);
+}
+
+fn index_into_last() {
+    let x = vec![2, 3, 5];
+    let _ = x[x.len() - 1];
+}
+
+fn use_last_with_different_vec_length() {
+    let x = vec![2, 3, 5];
+    let y = vec!['a', 'b', 'c'];
+    let _ = x.get(y.len() - 1);
+}
+
+fn main() {
+    dont_use_last();
+    indexing_two_from_end();
+    index_into_last();
+    use_last_with_different_vec_length();
+}
diff --git a/src/tools/clippy/tests/ui/get_last_with_len.stderr b/src/tools/clippy/tests/ui/get_last_with_len.stderr
new file mode 100644
index 00000000000..55baf87384a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_last_with_len.stderr
@@ -0,0 +1,10 @@
+error: accessing last element with `x.get(x.len() - 1)`
+  --> $DIR/get_last_with_len.rs:7:13
+   |
+LL |     let _ = x.get(x.len() - 1); // ~ERROR Use x.last()
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `x.last()`
+   |
+   = note: `-D clippy::get-last-with-len` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
new file mode 100644
index 00000000000..97e6b20f471
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -0,0 +1,62 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![deny(clippy::get_unwrap)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+use std::iter::FromIterator;
+
+struct GetFalsePositive {
+    arr: [u32; 3],
+}
+
+impl GetFalsePositive {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
+}
+
+fn main() {
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_slice = &mut [0, 1, 2, 3];
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
+    let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
+
+    {
+        // Test `get().unwrap()`
+        let _ = &boxed_slice[1];
+        let _ = &some_slice[0];
+        let _ = &some_vec[0];
+        let _ = &some_vecdeque[0];
+        let _ = &some_hashmap[&1];
+        let _ = &some_btreemap[&1];
+        let _ = false_positive.get(0).unwrap();
+        // Test with deref
+        let _: u8 = boxed_slice[1];
+    }
+
+    {
+        // Test `get_mut().unwrap()`
+        boxed_slice[0] = 1;
+        some_slice[0] = 1;
+        some_vec[0] = 1;
+        some_vecdeque[0] = 1;
+        // Check false positives
+        *some_hashmap.get_mut(&1).unwrap() = 'b';
+        *some_btreemap.get_mut(&1).unwrap() = 'b';
+        *false_positive.get_mut(0).unwrap() = 1;
+    }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec[0..1].to_vec();
+        let _ = some_vec[0..1].to_vec();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
new file mode 100644
index 00000000000..1c9a71c0969
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -0,0 +1,62 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![deny(clippy::get_unwrap)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+use std::iter::FromIterator;
+
+struct GetFalsePositive {
+    arr: [u32; 3],
+}
+
+impl GetFalsePositive {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
+}
+
+fn main() {
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_slice = &mut [0, 1, 2, 3];
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
+    let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
+
+    {
+        // Test `get().unwrap()`
+        let _ = boxed_slice.get(1).unwrap();
+        let _ = some_slice.get(0).unwrap();
+        let _ = some_vec.get(0).unwrap();
+        let _ = some_vecdeque.get(0).unwrap();
+        let _ = some_hashmap.get(&1).unwrap();
+        let _ = some_btreemap.get(&1).unwrap();
+        let _ = false_positive.get(0).unwrap();
+        // Test with deref
+        let _: u8 = *boxed_slice.get(1).unwrap();
+    }
+
+    {
+        // Test `get_mut().unwrap()`
+        *boxed_slice.get_mut(0).unwrap() = 1;
+        *some_slice.get_mut(0).unwrap() = 1;
+        *some_vec.get_mut(0).unwrap() = 1;
+        *some_vecdeque.get_mut(0).unwrap() = 1;
+        // Check false positives
+        *some_hashmap.get_mut(&1).unwrap() = 'b';
+        *some_btreemap.get_mut(&1).unwrap() = 'b';
+        *false_positive.get_mut(0).unwrap() = 1;
+    }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec.get(0..1).unwrap().to_vec();
+        let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
new file mode 100644
index 00000000000..76a098df82a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -0,0 +1,86 @@
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:34:17
+   |
+LL |         let _ = boxed_slice.get(1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+   |
+note: the lint level is defined here
+  --> $DIR/get_unwrap.rs:3:9
+   |
+LL | #![deny(clippy::get_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:35:17
+   |
+LL |         let _ = some_slice.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
+
+error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:36:17
+   |
+LL |         let _ = some_vec.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
+
+error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:37:17
+   |
+LL |         let _ = some_vecdeque.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
+
+error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:38:17
+   |
+LL |         let _ = some_hashmap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
+
+error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:39:17
+   |
+LL |         let _ = some_btreemap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:42:21
+   |
+LL |         let _: u8 = *boxed_slice.get(1).unwrap();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
+
+error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:47:9
+   |
+LL |         *boxed_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
+
+error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:48:9
+   |
+LL |         *some_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
+
+error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:49:9
+   |
+LL |         *some_vec.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
+
+error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:50:9
+   |
+LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
+
+error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:59:17
+   |
+LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+
+error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:60:17
+   |
+LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/identity_conversion.fixed b/src/tools/clippy/tests/ui/identity_conversion.fixed
new file mode 100644
index 00000000000..dd3fc56e98b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/identity_conversion.fixed
@@ -0,0 +1,58 @@
+// run-rustfix
+
+#![deny(clippy::identity_conversion)]
+
+fn test_generic<T: Copy>(val: T) -> T {
+    let _ = val;
+    val
+}
+
+fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
+    // ok
+    let _: i32 = val.into();
+    let _: U = val.into();
+    let _ = U::from(val);
+}
+
+fn test_questionmark() -> Result<(), ()> {
+    {
+        let _: i32 = 0i32;
+        Ok(Ok(()))
+    }??;
+    Ok(())
+}
+
+fn test_issue_3913() -> Result<(), std::io::Error> {
+    use std::fs;
+    use std::path::Path;
+
+    let path = Path::new(".");
+    for _ in fs::read_dir(path)? {}
+
+    Ok(())
+}
+
+fn main() {
+    test_generic(10i32);
+    test_generic2::<i32, i32>(10i32);
+    test_questionmark().unwrap();
+    test_issue_3913().unwrap();
+
+    let _: String = "foo".into();
+    let _: String = From::from("foo");
+    let _ = String::from("foo");
+    #[allow(clippy::identity_conversion)]
+    {
+        let _: String = "foo".into();
+        let _ = String::from("foo");
+        let _ = "".lines().into_iter();
+    }
+
+    let _: String = "foo".to_string();
+    let _: String = "foo".to_string();
+    let _ = "foo".to_string();
+    let _ = format!("A: {:04}", 123);
+    let _ = "".lines();
+    let _ = vec![1, 2, 3].into_iter();
+    let _: String = format!("Hello {}", "world");
+}
diff --git a/src/tools/clippy/tests/ui/identity_conversion.rs b/src/tools/clippy/tests/ui/identity_conversion.rs
new file mode 100644
index 00000000000..875ed7db373
--- /dev/null
+++ b/src/tools/clippy/tests/ui/identity_conversion.rs
@@ -0,0 +1,58 @@
+// run-rustfix
+
+#![deny(clippy::identity_conversion)]
+
+fn test_generic<T: Copy>(val: T) -> T {
+    let _ = T::from(val);
+    val.into()
+}
+
+fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
+    // ok
+    let _: i32 = val.into();
+    let _: U = val.into();
+    let _ = U::from(val);
+}
+
+fn test_questionmark() -> Result<(), ()> {
+    {
+        let _: i32 = 0i32.into();
+        Ok(Ok(()))
+    }??;
+    Ok(())
+}
+
+fn test_issue_3913() -> Result<(), std::io::Error> {
+    use std::fs;
+    use std::path::Path;
+
+    let path = Path::new(".");
+    for _ in fs::read_dir(path)? {}
+
+    Ok(())
+}
+
+fn main() {
+    test_generic(10i32);
+    test_generic2::<i32, i32>(10i32);
+    test_questionmark().unwrap();
+    test_issue_3913().unwrap();
+
+    let _: String = "foo".into();
+    let _: String = From::from("foo");
+    let _ = String::from("foo");
+    #[allow(clippy::identity_conversion)]
+    {
+        let _: String = "foo".into();
+        let _ = String::from("foo");
+        let _ = "".lines().into_iter();
+    }
+
+    let _: String = "foo".to_string().into();
+    let _: String = From::from("foo".to_string());
+    let _ = String::from("foo".to_string());
+    let _ = String::from(format!("A: {:04}", 123));
+    let _ = "".lines().into_iter();
+    let _ = vec![1, 2, 3].into_iter().into_iter();
+    let _: String = format!("Hello {}", "world").into();
+}
diff --git a/src/tools/clippy/tests/ui/identity_conversion.stderr b/src/tools/clippy/tests/ui/identity_conversion.stderr
new file mode 100644
index 00000000000..57626b23795
--- /dev/null
+++ b/src/tools/clippy/tests/ui/identity_conversion.stderr
@@ -0,0 +1,68 @@
+error: identical conversion
+  --> $DIR/identity_conversion.rs:6:13
+   |
+LL |     let _ = T::from(val);
+   |             ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
+   |
+note: the lint level is defined here
+  --> $DIR/identity_conversion.rs:3:9
+   |
+LL | #![deny(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:7:5
+   |
+LL |     val.into()
+   |     ^^^^^^^^^^ help: consider removing `.into()`: `val`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:19:22
+   |
+LL |         let _: i32 = 0i32.into();
+   |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:51:21
+   |
+LL |     let _: String = "foo".to_string().into();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:52:21
+   |
+LL |     let _: String = From::from("foo".to_string());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:53:13
+   |
+LL |     let _ = String::from("foo".to_string());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:54:13
+   |
+LL |     let _ = String::from(format!("A: {:04}", 123));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:55:13
+   |
+LL |     let _ = "".lines().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:56:13
+   |
+LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:57:21
+   |
+LL |     let _: String = format!("Hello {}", "world").into();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
new file mode 100644
index 00000000000..ae2815d345a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -0,0 +1,36 @@
+const ONE: i64 = 1;
+const NEG_ONE: i64 = -1;
+const ZERO: i64 = 0;
+
+#[allow(
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::double_parens
+)]
+#[warn(clippy::identity_op)]
+#[rustfmt::skip]
+fn main() {
+    let x = 0;
+
+    x + 0;
+    x + (1 - 1);
+    x + 1;
+    0 + x;
+    1 + x;
+    x - ZERO; //no error, as we skip lookups (for now)
+    x | (0);
+    ((ZERO)) | x; //no error, as we skip lookups (for now)
+
+    x * 1;
+    1 * x;
+    x / ONE; //no error, as we skip lookups (for now)
+
+    x / 2; //no false positive
+
+    x & NEG_ONE; //no error, as we skip lookups (for now)
+    -1 & x;
+
+    let u: u8 = 0;
+    u & 255;
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
new file mode 100644
index 00000000000..4742877706a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -0,0 +1,52 @@
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:16:5
+   |
+LL |     x + 0;
+   |     ^^^^^
+   |
+   = note: `-D clippy::identity-op` implied by `-D warnings`
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:17:5
+   |
+LL |     x + (1 - 1);
+   |     ^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:19:5
+   |
+LL |     0 + x;
+   |     ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:22:5
+   |
+LL |     x | (0);
+   |     ^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:25:5
+   |
+LL |     x * 1;
+   |     ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:26:5
+   |
+LL |     1 * x;
+   |     ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `x`
+  --> $DIR/identity_op.rs:32:5
+   |
+LL |     -1 & x;
+   |     ^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `u`
+  --> $DIR/identity_op.rs:35:5
+   |
+LL |     u & 255;
+   |     ^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.rs b/src/tools/clippy/tests/ui/if_let_mutex.rs
new file mode 100644
index 00000000000..58feae422a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_let_mutex.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::if_let_mutex)]
+
+use std::ops::Deref;
+use std::sync::Mutex;
+
+fn do_stuff<T>(_: T) {}
+
+fn if_let() {
+    let m = Mutex::new(1_u8);
+    if let Err(locked) = m.lock() {
+        do_stuff(locked);
+    } else {
+        let lock = m.lock().unwrap();
+        do_stuff(lock);
+    };
+}
+
+// This is the most common case as the above case is pretty
+// contrived.
+fn if_let_option() {
+    let m = Mutex::new(Some(0_u8));
+    if let Some(locked) = m.lock().unwrap().deref() {
+        do_stuff(locked);
+    } else {
+        let lock = m.lock().unwrap();
+        do_stuff(lock);
+    };
+}
+
+// When mutexs are different don't warn
+fn if_let_different_mutex() {
+    let m = Mutex::new(Some(0_u8));
+    let other = Mutex::new(None::<u8>);
+    if let Some(locked) = m.lock().unwrap().deref() {
+        do_stuff(locked);
+    } else {
+        let lock = other.lock().unwrap();
+        do_stuff(lock);
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.stderr b/src/tools/clippy/tests/ui/if_let_mutex.stderr
new file mode 100644
index 00000000000..e9c4d916332
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_let_mutex.stderr
@@ -0,0 +1,29 @@
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> $DIR/if_let_mutex.rs:10:5
+   |
+LL | /     if let Err(locked) = m.lock() {
+LL | |         do_stuff(locked);
+LL | |     } else {
+LL | |         let lock = m.lock().unwrap();
+LL | |         do_stuff(lock);
+LL | |     };
+   | |_____^
+   |
+   = note: `-D clippy::if-let-mutex` implied by `-D warnings`
+   = help: move the lock call outside of the `if let ...` expression
+
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> $DIR/if_let_mutex.rs:22:5
+   |
+LL | /     if let Some(locked) = m.lock().unwrap().deref() {
+LL | |         do_stuff(locked);
+LL | |     } else {
+LL | |         let lock = m.lock().unwrap();
+LL | |         do_stuff(lock);
+LL | |     };
+   | |_____^
+   |
+   = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.fixed b/src/tools/clippy/tests/ui/if_let_some_result.fixed
new file mode 100644
index 00000000000..80505fd997f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_let_some_result.fixed
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![warn(clippy::if_let_some_result)]
+
+fn str_to_int(x: &str) -> i32 {
+    if let Ok(y) = x.parse() {
+        y
+    } else {
+        0
+    }
+}
+
+fn str_to_int_ok(x: &str) -> i32 {
+    if let Ok(y) = x.parse() {
+        y
+    } else {
+        0
+    }
+}
+
+#[rustfmt::skip]
+fn strange_some_no_else(x: &str) -> i32 {
+    {
+        if let Ok(y) = x   .   parse()       {
+            return y;
+        };
+        0
+    }
+}
+
+fn main() {
+    let _ = str_to_int("1");
+    let _ = str_to_int_ok("2");
+    let _ = strange_some_no_else("3");
+}
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.rs b/src/tools/clippy/tests/ui/if_let_some_result.rs
new file mode 100644
index 00000000000..ecac1357445
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_let_some_result.rs
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![warn(clippy::if_let_some_result)]
+
+fn str_to_int(x: &str) -> i32 {
+    if let Some(y) = x.parse().ok() {
+        y
+    } else {
+        0
+    }
+}
+
+fn str_to_int_ok(x: &str) -> i32 {
+    if let Ok(y) = x.parse() {
+        y
+    } else {
+        0
+    }
+}
+
+#[rustfmt::skip]
+fn strange_some_no_else(x: &str) -> i32 {
+    {
+        if let Some(y) = x   .   parse()   .   ok   ()    {
+            return y;
+        };
+        0
+    }
+}
+
+fn main() {
+    let _ = str_to_int("1");
+    let _ = str_to_int_ok("2");
+    let _ = strange_some_no_else("3");
+}
diff --git a/src/tools/clippy/tests/ui/if_let_some_result.stderr b/src/tools/clippy/tests/ui/if_let_some_result.stderr
new file mode 100644
index 00000000000..334ccb01016
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_let_some_result.stderr
@@ -0,0 +1,25 @@
+error: Matching on `Some` with `ok()` is redundant
+  --> $DIR/if_let_some_result.rs:6:5
+   |
+LL |     if let Some(y) = x.parse().ok() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::if-let-some-result` implied by `-D warnings`
+help: Consider matching on `Ok(y)` and removing the call to `ok` instead
+   |
+LL |     if let Ok(y) = x.parse() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Matching on `Some` with `ok()` is redundant
+  --> $DIR/if_let_some_result.rs:24:9
+   |
+LL |         if let Some(y) = x   .   parse()   .   ok   ()    {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: Consider matching on `Ok(y)` and removing the call to `ok` instead
+   |
+LL |         if let Ok(y) = x   .   parse()       {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/if_not_else.rs b/src/tools/clippy/tests/ui/if_not_else.rs
new file mode 100644
index 00000000000..dc3fb1ceac9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_not_else.rs
@@ -0,0 +1,19 @@
+#![warn(clippy::all)]
+#![warn(clippy::if_not_else)]
+
+fn bla() -> bool {
+    unimplemented!()
+}
+
+fn main() {
+    if !bla() {
+        println!("Bugs");
+    } else {
+        println!("Bunny");
+    }
+    if 4 != 5 {
+        println!("Bugs");
+    } else {
+        println!("Bunny");
+    }
+}
diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr
new file mode 100644
index 00000000000..78bc4d4bd20
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_not_else.stderr
@@ -0,0 +1,27 @@
+error: Unnecessary boolean `not` operation
+  --> $DIR/if_not_else.rs:9:5
+   |
+LL | /     if !bla() {
+LL | |         println!("Bugs");
+LL | |     } else {
+LL | |         println!("Bunny");
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::if-not-else` implied by `-D warnings`
+   = help: remove the `!` and swap the blocks of the `if`/`else`
+
+error: Unnecessary `!=` operation
+  --> $DIR/if_not_else.rs:14:5
+   |
+LL | /     if 4 != 5 {
+LL | |         println!("Bugs");
+LL | |     } else {
+LL | |         println!("Bunny");
+LL | |     }
+   | |_____^
+   |
+   = help: change to `==` and swap the blocks of the `if`/`else`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
new file mode 100644
index 00000000000..6bbf79edfcf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -0,0 +1,145 @@
+#![warn(clippy::if_same_then_else)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::eq_op,
+    clippy::never_loop,
+    clippy::no_effect,
+    clippy::unused_unit,
+    clippy::zero_divided_by_zero
+)]
+
+struct Foo {
+    bar: u8,
+}
+
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn if_same_then_else() {
+    if true {
+        Foo { bar: 42 };
+        0..10;
+        ..;
+        0..;
+        ..10;
+        0..=10;
+        foo();
+    } else {
+        //~ ERROR same body as `if` block
+        Foo { bar: 42 };
+        0..10;
+        ..;
+        0..;
+        ..10;
+        0..=10;
+        foo();
+    }
+
+    if true {
+        Foo { bar: 42 };
+    } else {
+        Foo { bar: 43 };
+    }
+
+    if true {
+        ();
+    } else {
+        ()
+    }
+
+    if true {
+        0..10;
+    } else {
+        0..=10;
+    }
+
+    if true {
+        foo();
+        foo();
+    } else {
+        foo();
+    }
+
+    let _ = if true {
+        0.0
+    } else {
+        //~ ERROR same body as `if` block
+        0.0
+    };
+
+    let _ = if true {
+        -0.0
+    } else {
+        //~ ERROR same body as `if` block
+        -0.0
+    };
+
+    let _ = if true { 0.0 } else { -0.0 };
+
+    // Different NaNs
+    let _ = if true { 0.0 / 0.0 } else { f32::NAN };
+
+    if true {
+        foo();
+    }
+
+    let _ = if true {
+        42
+    } else {
+        //~ ERROR same body as `if` block
+        42
+    };
+
+    if true {
+        let bar = if true { 42 } else { 43 };
+
+        while foo() {
+            break;
+        }
+        bar + 1;
+    } else {
+        //~ ERROR same body as `if` block
+        let bar = if true { 42 } else { 43 };
+
+        while foo() {
+            break;
+        }
+        bar + 1;
+    }
+
+    if true {
+        let _ = match 42 {
+            42 => 1,
+            a if a > 0 => 2,
+            10..=15 => 3,
+            _ => 4,
+        };
+    } else if false {
+        foo();
+    } else if foo() {
+        let _ = match 42 {
+            42 => 1,
+            a if a > 0 => 2,
+            10..=15 => 3,
+            _ => 4,
+        };
+    }
+}
+
+// Issue #2423. This was causing an ICE.
+fn func() {
+    if true {
+        f(&[0; 62]);
+        f(&[0; 4]);
+        f(&[0; 3]);
+    } else {
+        f(&[0; 62]);
+        f(&[0; 6]);
+        f(&[0; 6]);
+    }
+}
+
+fn f(val: &[u8]) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
new file mode 100644
index 00000000000..d9fdf06fa8b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -0,0 +1,112 @@
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:28:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         Foo { bar: 42 };
+LL | |         0..10;
+...  |
+LL | |         foo();
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
+note: same as this
+  --> $DIR/if_same_then_else.rs:20:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         Foo { bar: 42 };
+LL | |         0..10;
+LL | |         ..;
+...  |
+LL | |         foo();
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:66:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         0.0
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:64:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         0.0
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:73:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         -0.0
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:71:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         -0.0
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:89:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         42
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:87:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         42
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:101:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         let bar = if true { 42 } else { 43 };
+LL | |
+...  |
+LL | |         bar + 1;
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:94:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         let bar = if true { 42 } else { 43 };
+LL | |
+LL | |         while foo() {
+...  |
+LL | |         bar + 1;
+LL | |     } else {
+   | |_____^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
new file mode 100644
index 00000000000..3cc21809264
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -0,0 +1,139 @@
+#![warn(clippy::if_same_then_else)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::collapsible_if,
+    clippy::ifs_same_cond,
+    clippy::needless_return
+)]
+
+fn if_same_then_else2() -> Result<&'static str, ()> {
+    if true {
+        for _ in &[42] {
+            let foo: &Option<_> = &Some::<u8>(42);
+            if true {
+                break;
+            } else {
+                continue;
+            }
+        }
+    } else {
+        //~ ERROR same body as `if` block
+        for _ in &[42] {
+            let foo: &Option<_> = &Some::<u8>(42);
+            if true {
+                break;
+            } else {
+                continue;
+            }
+        }
+    }
+
+    if true {
+        if let Some(a) = Some(42) {}
+    } else {
+        //~ ERROR same body as `if` block
+        if let Some(a) = Some(42) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        //~ ERROR same body as `if` block
+        if let (1, .., 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 4) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 1, 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let Some(42) = None {}
+    } else {
+        if let Option::Some(42) = None {}
+    }
+
+    if true {
+        if let Some(42) = None::<u8> {}
+    } else {
+        if let Some(42) = None {}
+    }
+
+    if true {
+        if let Some(42) = None::<u8> {}
+    } else {
+        if let Some(42) = None::<u32> {}
+    }
+
+    if true {
+        if let Some(a) = Some(42) {}
+    } else {
+        if let Some(a) = Some(43) {}
+    }
+
+    // Same NaNs
+    let _ = if true {
+        f32::NAN
+    } else {
+        //~ ERROR same body as `if` block
+        f32::NAN
+    };
+
+    if true {
+        Ok("foo")?;
+    } else {
+        //~ ERROR same body as `if` block
+        Ok("foo")?;
+    }
+
+    if true {
+        let foo = "";
+        return Ok(&foo[0..]);
+    } else if false {
+        let foo = "bar";
+        return Ok(&foo[0..]);
+    } else {
+        let foo = "";
+        return Ok(&foo[0..]);
+    }
+
+    if true {
+        let foo = "";
+        return Ok(&foo[0..]);
+    } else if false {
+        let foo = "bar";
+        return Ok(&foo[0..]);
+    } else if true {
+        let foo = "";
+        return Ok(&foo[0..]);
+    } else {
+        let foo = "";
+        return Ok(&foo[0..]);
+    }
+
+    // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559.
+    if true {
+        let foo = "";
+        let (x, y) = (1, 2);
+        return Ok(&foo[x..y]);
+    } else {
+        let foo = "";
+        let (y, x) = (1, 2);
+        return Ok(&foo[x..y]);
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
new file mode 100644
index 00000000000..f5d087fe128
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
@@ -0,0 +1,125 @@
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:19:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         for _ in &[42] {
+LL | |             let foo: &Option<_> = &Some::<u8>(42);
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
+note: same as this
+  --> $DIR/if_same_then_else2.rs:10:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         for _ in &[42] {
+LL | |             let foo: &Option<_> = &Some::<u8>(42);
+LL | |             if true {
+...  |
+LL | |         }
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:33:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         if let Some(a) = Some(42) {}
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:31:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         if let Some(a) = Some(42) {}
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:40:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:38:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:90:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         f32::NAN
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:88:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         f32::NAN
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:97:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         Ok("foo")?;
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:95:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         Ok("foo")?;
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else2.rs:122:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         let foo = "";
+LL | |         return Ok(&foo[0..]);
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else2.rs:119:20
+   |
+LL |       } else if true {
+   |  ____________________^
+LL | |         let foo = "";
+LL | |         return Ok(&foo[0..]);
+LL | |     } else {
+   | |_____^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
new file mode 100644
index 00000000000..80e9839ff40
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -0,0 +1,46 @@
+#![warn(clippy::ifs_same_cond)]
+#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks
+
+fn ifs_same_cond() {
+    let a = 0;
+    let b = false;
+
+    if b {
+    } else if b {
+        //~ ERROR ifs same condition
+    }
+
+    if a == 1 {
+    } else if a == 1 {
+        //~ ERROR ifs same condition
+    }
+
+    if 2 * a == 1 {
+    } else if 2 * a == 2 {
+    } else if 2 * a == 1 {
+        //~ ERROR ifs same condition
+    } else if a == 1 {
+    }
+
+    // See #659
+    if cfg!(feature = "feature1-659") {
+        1
+    } else if cfg!(feature = "feature2-659") {
+        2
+    } else {
+        3
+    };
+
+    let mut v = vec![1];
+    if v.pop() == None {
+        // ok, functions
+    } else if v.pop() == None {
+    }
+
+    if v.len() == 42 {
+        // ok, functions
+    } else if v.len() == 42 {
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
new file mode 100644
index 00000000000..0c8f49b8687
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -0,0 +1,39 @@
+error: this `if` has the same condition as a previous `if`
+  --> $DIR/ifs_same_cond.rs:9:15
+   |
+LL |     } else if b {
+   |               ^
+   |
+   = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
+note: same as this
+  --> $DIR/ifs_same_cond.rs:8:8
+   |
+LL |     if b {
+   |        ^
+
+error: this `if` has the same condition as a previous `if`
+  --> $DIR/ifs_same_cond.rs:14:15
+   |
+LL |     } else if a == 1 {
+   |               ^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:13:8
+   |
+LL |     if a == 1 {
+   |        ^^^^^^
+
+error: this `if` has the same condition as a previous `if`
+  --> $DIR/ifs_same_cond.rs:20:15
+   |
+LL |     } else if 2 * a == 1 {
+   |               ^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:18:8
+   |
+LL |     if 2 * a == 1 {
+   |        ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs
new file mode 100644
index 00000000000..1c46e3a5337
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl.rs
@@ -0,0 +1,36 @@
+#![allow(dead_code)]
+#![warn(clippy::multiple_inherent_impl)]
+
+struct MyStruct;
+
+impl MyStruct {
+    fn first() {}
+}
+
+impl MyStruct {
+    fn second() {}
+}
+
+impl<'a> MyStruct {
+    fn lifetimed() {}
+}
+
+mod submod {
+    struct MyStruct;
+    impl MyStruct {
+        fn other() {}
+    }
+
+    impl super::MyStruct {
+        fn third() {}
+    }
+}
+
+use std::fmt;
+impl fmt::Debug for MyStruct {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "MyStruct {{ }}")
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr
new file mode 100644
index 00000000000..585d32845d2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl.stderr
@@ -0,0 +1,35 @@
+error: Multiple implementations of this structure
+  --> $DIR/impl.rs:10:1
+   |
+LL | / impl MyStruct {
+LL | |     fn second() {}
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
+note: First implementation here
+  --> $DIR/impl.rs:6:1
+   |
+LL | / impl MyStruct {
+LL | |     fn first() {}
+LL | | }
+   | |_^
+
+error: Multiple implementations of this structure
+  --> $DIR/impl.rs:24:5
+   |
+LL | /     impl super::MyStruct {
+LL | |         fn third() {}
+LL | |     }
+   | |_____^
+   |
+note: First implementation here
+  --> $DIR/impl.rs:6:1
+   |
+LL | / impl MyStruct {
+LL | |     fn first() {}
+LL | | }
+   | |_^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs
new file mode 100644
index 00000000000..fdcc9a33f55
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_hasher.rs
@@ -0,0 +1,99 @@
+// aux-build:implicit_hasher_macros.rs
+#![deny(clippy::implicit_hasher)]
+#![allow(unused)]
+
+#[macro_use]
+extern crate implicit_hasher_macros;
+
+use std::cmp::Eq;
+use std::collections::{HashMap, HashSet};
+use std::hash::{BuildHasher, Hash};
+
+pub trait Foo<T>: Sized {
+    fn make() -> (Self, Self);
+}
+
+impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
+    fn make() -> (Self, Self) {
+        // OK, don't suggest to modify these
+        let _: HashMap<i32, i32> = HashMap::new();
+        let _: HashSet<i32> = HashSet::new();
+
+        (HashMap::new(), HashMap::with_capacity(10))
+    }
+}
+impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
+    fn make() -> (Self, Self) {
+        ((HashMap::new(),), (HashMap::with_capacity(10),))
+    }
+}
+impl Foo<i16> for HashMap<String, String> {
+    fn make() -> (Self, Self) {
+        (HashMap::new(), HashMap::with_capacity(10))
+    }
+}
+
+impl<K: Hash + Eq, V, S: BuildHasher + Default> Foo<i32> for HashMap<K, V, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashMap<String, String, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
+    fn make() -> (Self, Self) {
+        (HashSet::new(), HashSet::with_capacity(10))
+    }
+}
+impl Foo<i16> for HashSet<String> {
+    fn make() -> (Self, Self) {
+        (HashSet::new(), HashSet::with_capacity(10))
+    }
+}
+
+impl<T: Hash + Eq, S: BuildHasher + Default> Foo<i32> for HashSet<T, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+
+macro_rules! gen {
+    (impl) => {
+        impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
+            fn make() -> (Self, Self) {
+                (HashMap::new(), HashMap::with_capacity(10))
+            }
+        }
+    };
+
+    (fn $name:ident) => {
+        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+    };
+}
+#[rustfmt::skip]
+gen!(impl);
+gen!(fn bar);
+
+// When the macro is in a different file, the suggestion spans can't be combined properly
+// and should not cause an ICE
+// See #2707
+#[macro_use]
+#[path = "../auxiliary/test_macro.rs"]
+pub mod test_macro;
+__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
+
+// #4260
+implicit_hasher_fn!();
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr
new file mode 100644
index 00000000000..2b06d661772
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr
@@ -0,0 +1,153 @@
+error: impl for `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:16:35
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
+   |                                   ^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/implicit_hasher.rs:2:9
+   |
+LL | #![deny(clippy::implicit_hasher)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+help: consider adding a type parameter
+   |
+LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:25:36
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
+   |                                    ^^^^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+   |           ^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:30:19
+   |
+LL | impl Foo<i16> for HashMap<String, String> {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: impl for `HashSet` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:47:32
+   |
+LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
+   |                                ^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+   |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: impl for `HashSet` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:52:19
+   |
+LL | impl Foo<i16> for HashSet<String> {
+   |                   ^^^^^^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+   |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:69:23
+   |
+LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                       ^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^            ^^^^^^^^^^^^^^^^^^^^
+
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:69:53
+   |
+LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                                                     ^^^^^^^^^^^^
+   |
+help: consider adding a type parameter
+   |
+LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                          ^^^^^^^^^^^^^^^
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:73:43
+   |
+LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
+   |                                           ^^^^^^^^^^^^^
+...
+LL | gen!(impl);
+   | ----------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider adding a type parameter
+   |
+LL |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |                  ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:81:33
+   |
+LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                                 ^^^^^^^^^^^^^^^^^
+...
+LL | gen!(fn bar);
+   | ------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider adding a type parameter
+   |
+LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^            ^^^^^^^^^^^^^^^^^^^^
+
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> $DIR/implicit_hasher.rs:81:63
+   |
+LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                                                               ^^^^^^^^^^^^
+...
+LL | gen!(fn bar);
+   | ------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider adding a type parameter
+   |
+LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                          ^^^^^^^^^^^^^^^
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed
new file mode 100644
index 00000000000..9066dc3fedf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_return.fixed
@@ -0,0 +1,101 @@
+// run-rustfix
+
+#![warn(clippy::implicit_return)]
+#![allow(clippy::needless_return, unused)]
+
+fn test_end_of_fn() -> bool {
+    if true {
+        // no error!
+        return true;
+    }
+
+    return true
+}
+
+#[allow(clippy::needless_bool)]
+fn test_if_block() -> bool {
+    if true {
+        return true
+    } else {
+        return false
+    }
+}
+
+#[rustfmt::skip]
+fn test_match(x: bool) -> bool {
+    match x {
+        true => return false,
+        false => { return true },
+    }
+}
+
+#[allow(clippy::needless_return)]
+fn test_match_with_unreachable(x: bool) -> bool {
+    match x {
+        true => return false,
+        false => unreachable!(),
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop() -> bool {
+    loop {
+        return true;
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_block() -> bool {
+    loop {
+        {
+            return true;
+        }
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_nests() -> bool {
+    loop {
+        if true {
+            return true;
+        } else {
+            let _ = true;
+        }
+    }
+}
+
+#[allow(clippy::redundant_pattern_matching)]
+fn test_loop_with_if_let() -> bool {
+    loop {
+        if let Some(x) = Some(true) {
+            return x;
+        }
+    }
+}
+
+fn test_closure() {
+    #[rustfmt::skip]
+    let _ = || { return true };
+    let _ = || return true;
+}
+
+fn test_panic() -> bool {
+    panic!()
+}
+
+fn test_return_macro() -> String {
+    return format!("test {}", "test")
+}
+
+fn main() {
+    let _ = test_end_of_fn();
+    let _ = test_if_block();
+    let _ = test_match(true);
+    let _ = test_match_with_unreachable(true);
+    let _ = test_loop();
+    let _ = test_loop_with_block();
+    let _ = test_loop_with_nests();
+    let _ = test_loop_with_if_let();
+    test_closure();
+    let _ = test_return_macro();
+}
diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs
new file mode 100644
index 00000000000..c0d70ecf502
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_return.rs
@@ -0,0 +1,101 @@
+// run-rustfix
+
+#![warn(clippy::implicit_return)]
+#![allow(clippy::needless_return, unused)]
+
+fn test_end_of_fn() -> bool {
+    if true {
+        // no error!
+        return true;
+    }
+
+    true
+}
+
+#[allow(clippy::needless_bool)]
+fn test_if_block() -> bool {
+    if true {
+        true
+    } else {
+        false
+    }
+}
+
+#[rustfmt::skip]
+fn test_match(x: bool) -> bool {
+    match x {
+        true => false,
+        false => { true },
+    }
+}
+
+#[allow(clippy::needless_return)]
+fn test_match_with_unreachable(x: bool) -> bool {
+    match x {
+        true => return false,
+        false => unreachable!(),
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop() -> bool {
+    loop {
+        break true;
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_block() -> bool {
+    loop {
+        {
+            break true;
+        }
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_nests() -> bool {
+    loop {
+        if true {
+            break true;
+        } else {
+            let _ = true;
+        }
+    }
+}
+
+#[allow(clippy::redundant_pattern_matching)]
+fn test_loop_with_if_let() -> bool {
+    loop {
+        if let Some(x) = Some(true) {
+            return x;
+        }
+    }
+}
+
+fn test_closure() {
+    #[rustfmt::skip]
+    let _ = || { true };
+    let _ = || true;
+}
+
+fn test_panic() -> bool {
+    panic!()
+}
+
+fn test_return_macro() -> String {
+    format!("test {}", "test")
+}
+
+fn main() {
+    let _ = test_end_of_fn();
+    let _ = test_if_block();
+    let _ = test_match(true);
+    let _ = test_match_with_unreachable(true);
+    let _ = test_loop();
+    let _ = test_loop_with_block();
+    let _ = test_loop_with_nests();
+    let _ = test_loop_with_if_let();
+    test_closure();
+    let _ = test_return_macro();
+}
diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr
new file mode 100644
index 00000000000..fb2ec902764
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_return.stderr
@@ -0,0 +1,70 @@
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:12:5
+   |
+LL |     true
+   |     ^^^^ help: add `return` as shown: `return true`
+   |
+   = note: `-D clippy::implicit-return` implied by `-D warnings`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:18:9
+   |
+LL |         true
+   |         ^^^^ help: add `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:20:9
+   |
+LL |         false
+   |         ^^^^^ help: add `return` as shown: `return false`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:27:17
+   |
+LL |         true => false,
+   |                 ^^^^^ help: add `return` as shown: `return false`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:28:20
+   |
+LL |         false => { true },
+   |                    ^^^^ help: add `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:43:9
+   |
+LL |         break true;
+   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:51:13
+   |
+LL |             break true;
+   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:60:13
+   |
+LL |             break true;
+   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:78:18
+   |
+LL |     let _ = || { true };
+   |                  ^^^^ help: add `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:79:16
+   |
+LL |     let _ = || true;
+   |                ^^^^ help: add `return` as shown: `return true`
+
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:87:5
+   |
+LL |     format!("test {}", "test")
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
new file mode 100644
index 00000000000..e0b5b31a00c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
@@ -0,0 +1,160 @@
+// run-rustfix
+#![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
+#![warn(clippy::implicit_saturating_sub)]
+
+fn main() {
+    // Tests for unsigned integers
+
+    let end_8: u8 = 10;
+    let start_8: u8 = 5;
+    let mut u_8: u8 = end_8 - start_8;
+
+    // Lint
+    u_8 = u_8.saturating_sub(1);
+
+    match end_8 {
+        10 => {
+            // Lint
+            u_8 = u_8.saturating_sub(1);
+        },
+        11 => u_8 += 1,
+        _ => u_8 = 0,
+    }
+
+    let end_16: u16 = 40;
+    let start_16: u16 = 35;
+
+    let mut u_16: u16 = end_16 - start_16;
+
+    // Lint
+    u_16 = u_16.saturating_sub(1);
+
+    let mut end_32: u32 = 7000;
+    let mut start_32: u32 = 7010;
+
+    let mut u_32: u32 = end_32 - start_32;
+
+    // Lint
+    u_32 = u_32.saturating_sub(1);
+
+    // No Lint
+    if u_32 > 0 {
+        u_16 += 1;
+    }
+
+    // No Lint
+    if u_32 != 0 {
+        end_32 -= 1;
+        start_32 += 1;
+    }
+
+    let mut end_64: u64 = 75001;
+    let mut start_64: u64 = 75000;
+
+    let mut u_64: u64 = end_64 - start_64;
+
+    // Lint
+    u_64 = u_64.saturating_sub(1);
+
+    // Lint
+    u_64 = u_64.saturating_sub(1);
+
+    // Lint
+    u_64 = u_64.saturating_sub(1);
+
+    // No Lint
+    if u_64 >= 1 {
+        u_64 -= 1;
+    }
+
+    // No Lint
+    if u_64 > 0 {
+        end_64 -= 1;
+    }
+
+    // Tests for usize
+    let end_usize: usize = 8054;
+    let start_usize: usize = 8050;
+
+    let mut u_usize: usize = end_usize - start_usize;
+
+    // Lint
+    u_usize = u_usize.saturating_sub(1);
+
+    // Tests for signed integers
+
+    let endi_8: i8 = 10;
+    let starti_8: i8 = 50;
+
+    let mut i_8: i8 = endi_8 - starti_8;
+
+    // Lint
+    i_8 = i_8.saturating_sub(1);
+
+    // Lint
+    i_8 = i_8.saturating_sub(1);
+
+    // Lint
+    i_8 = i_8.saturating_sub(1);
+
+    // Lint
+    i_8 = i_8.saturating_sub(1);
+
+    let endi_16: i16 = 45;
+    let starti_16: i16 = 44;
+
+    let mut i_16: i16 = endi_16 - starti_16;
+
+    // Lint
+    i_16 = i_16.saturating_sub(1);
+
+    // Lint
+    i_16 = i_16.saturating_sub(1);
+
+    // Lint
+    i_16 = i_16.saturating_sub(1);
+
+    // Lint
+    i_16 = i_16.saturating_sub(1);
+
+    let endi_32: i32 = 45;
+    let starti_32: i32 = 44;
+
+    let mut i_32: i32 = endi_32 - starti_32;
+
+    // Lint
+    i_32 = i_32.saturating_sub(1);
+
+    // Lint
+    i_32 = i_32.saturating_sub(1);
+
+    // Lint
+    i_32 = i_32.saturating_sub(1);
+
+    // Lint
+    i_32 = i_32.saturating_sub(1);
+
+    let endi_64: i64 = 45;
+    let starti_64: i64 = 44;
+
+    let mut i_64: i64 = endi_64 - starti_64;
+
+    // Lint
+    i_64 = i_64.saturating_sub(1);
+
+    // Lint
+    i_64 = i_64.saturating_sub(1);
+
+    // Lint
+    i_64 = i_64.saturating_sub(1);
+
+    // No Lint
+    if i_64 > 0 {
+        i_64 -= 1;
+    }
+
+    // No Lint
+    if i_64 != 0 {
+        i_64 -= 1;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
new file mode 100644
index 00000000000..39d81608922
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
@@ -0,0 +1,206 @@
+// run-rustfix
+#![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
+#![warn(clippy::implicit_saturating_sub)]
+
+fn main() {
+    // Tests for unsigned integers
+
+    let end_8: u8 = 10;
+    let start_8: u8 = 5;
+    let mut u_8: u8 = end_8 - start_8;
+
+    // Lint
+    if u_8 > 0 {
+        u_8 = u_8 - 1;
+    }
+
+    match end_8 {
+        10 => {
+            // Lint
+            if u_8 > 0 {
+                u_8 -= 1;
+            }
+        },
+        11 => u_8 += 1,
+        _ => u_8 = 0,
+    }
+
+    let end_16: u16 = 40;
+    let start_16: u16 = 35;
+
+    let mut u_16: u16 = end_16 - start_16;
+
+    // Lint
+    if u_16 > 0 {
+        u_16 -= 1;
+    }
+
+    let mut end_32: u32 = 7000;
+    let mut start_32: u32 = 7010;
+
+    let mut u_32: u32 = end_32 - start_32;
+
+    // Lint
+    if u_32 != 0 {
+        u_32 -= 1;
+    }
+
+    // No Lint
+    if u_32 > 0 {
+        u_16 += 1;
+    }
+
+    // No Lint
+    if u_32 != 0 {
+        end_32 -= 1;
+        start_32 += 1;
+    }
+
+    let mut end_64: u64 = 75001;
+    let mut start_64: u64 = 75000;
+
+    let mut u_64: u64 = end_64 - start_64;
+
+    // Lint
+    if u_64 > 0 {
+        u_64 -= 1;
+    }
+
+    // Lint
+    if 0 < u_64 {
+        u_64 -= 1;
+    }
+
+    // Lint
+    if 0 != u_64 {
+        u_64 -= 1;
+    }
+
+    // No Lint
+    if u_64 >= 1 {
+        u_64 -= 1;
+    }
+
+    // No Lint
+    if u_64 > 0 {
+        end_64 -= 1;
+    }
+
+    // Tests for usize
+    let end_usize: usize = 8054;
+    let start_usize: usize = 8050;
+
+    let mut u_usize: usize = end_usize - start_usize;
+
+    // Lint
+    if u_usize > 0 {
+        u_usize -= 1;
+    }
+
+    // Tests for signed integers
+
+    let endi_8: i8 = 10;
+    let starti_8: i8 = 50;
+
+    let mut i_8: i8 = endi_8 - starti_8;
+
+    // Lint
+    if i_8 > i8::MIN {
+        i_8 -= 1;
+    }
+
+    // Lint
+    if i_8 > i8::min_value() {
+        i_8 -= 1;
+    }
+
+    // Lint
+    if i_8 != i8::MIN {
+        i_8 -= 1;
+    }
+
+    // Lint
+    if i_8 != i8::min_value() {
+        i_8 -= 1;
+    }
+
+    let endi_16: i16 = 45;
+    let starti_16: i16 = 44;
+
+    let mut i_16: i16 = endi_16 - starti_16;
+
+    // Lint
+    if i_16 > i16::MIN {
+        i_16 -= 1;
+    }
+
+    // Lint
+    if i_16 > i16::min_value() {
+        i_16 -= 1;
+    }
+
+    // Lint
+    if i_16 != i16::MIN {
+        i_16 -= 1;
+    }
+
+    // Lint
+    if i_16 != i16::min_value() {
+        i_16 -= 1;
+    }
+
+    let endi_32: i32 = 45;
+    let starti_32: i32 = 44;
+
+    let mut i_32: i32 = endi_32 - starti_32;
+
+    // Lint
+    if i_32 > i32::MIN {
+        i_32 -= 1;
+    }
+
+    // Lint
+    if i_32 > i32::min_value() {
+        i_32 -= 1;
+    }
+
+    // Lint
+    if i_32 != i32::MIN {
+        i_32 -= 1;
+    }
+
+    // Lint
+    if i_32 != i32::min_value() {
+        i_32 -= 1;
+    }
+
+    let endi_64: i64 = 45;
+    let starti_64: i64 = 44;
+
+    let mut i_64: i64 = endi_64 - starti_64;
+
+    // Lint
+    if i64::min_value() < i_64 {
+        i_64 -= 1;
+    }
+
+    // Lint
+    if i64::MIN != i_64 {
+        i_64 -= 1;
+    }
+
+    // Lint
+    if i64::MIN < i_64 {
+        i_64 -= 1;
+    }
+
+    // No Lint
+    if i_64 > 0 {
+        i_64 -= 1;
+    }
+
+    // No Lint
+    if i_64 != 0 {
+        i_64 -= 1;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
new file mode 100644
index 00000000000..a8ba870b1dd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
@@ -0,0 +1,188 @@
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:13:5
+   |
+LL | /     if u_8 > 0 {
+LL | |         u_8 = u_8 - 1;
+LL | |     }
+   | |_____^ help: try: `u_8 = u_8.saturating_sub(1);`
+   |
+   = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:20:13
+   |
+LL | /             if u_8 > 0 {
+LL | |                 u_8 -= 1;
+LL | |             }
+   | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:34:5
+   |
+LL | /     if u_16 > 0 {
+LL | |         u_16 -= 1;
+LL | |     }
+   | |_____^ help: try: `u_16 = u_16.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:44:5
+   |
+LL | /     if u_32 != 0 {
+LL | |         u_32 -= 1;
+LL | |     }
+   | |_____^ help: try: `u_32 = u_32.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:65:5
+   |
+LL | /     if u_64 > 0 {
+LL | |         u_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:70:5
+   |
+LL | /     if 0 < u_64 {
+LL | |         u_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:75:5
+   |
+LL | /     if 0 != u_64 {
+LL | |         u_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:96:5
+   |
+LL | /     if u_usize > 0 {
+LL | |         u_usize -= 1;
+LL | |     }
+   | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:108:5
+   |
+LL | /     if i_8 > i8::MIN {
+LL | |         i_8 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:113:5
+   |
+LL | /     if i_8 > i8::min_value() {
+LL | |         i_8 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:118:5
+   |
+LL | /     if i_8 != i8::MIN {
+LL | |         i_8 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:123:5
+   |
+LL | /     if i_8 != i8::min_value() {
+LL | |         i_8 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:133:5
+   |
+LL | /     if i_16 > i16::MIN {
+LL | |         i_16 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:138:5
+   |
+LL | /     if i_16 > i16::min_value() {
+LL | |         i_16 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:143:5
+   |
+LL | /     if i_16 != i16::MIN {
+LL | |         i_16 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:148:5
+   |
+LL | /     if i_16 != i16::min_value() {
+LL | |         i_16 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:158:5
+   |
+LL | /     if i_32 > i32::MIN {
+LL | |         i_32 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:163:5
+   |
+LL | /     if i_32 > i32::min_value() {
+LL | |         i_32 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:168:5
+   |
+LL | /     if i_32 != i32::MIN {
+LL | |         i_32 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:173:5
+   |
+LL | /     if i_32 != i32::min_value() {
+LL | |         i_32 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:183:5
+   |
+LL | /     if i64::min_value() < i_64 {
+LL | |         i_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:188:5
+   |
+LL | /     if i64::MIN != i_64 {
+LL | |         i_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
+
+error: Implicitly performing saturating subtraction
+  --> $DIR/implicit_saturating_sub.rs:193:5
+   |
+LL | /     if i64::MIN < i_64 {
+LL | |         i_64 -= 1;
+LL | |     }
+   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
+
+error: aborting due to 23 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
new file mode 100644
index 00000000000..b75f10917df
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
@@ -0,0 +1,43 @@
+// run-rustfix
+#[warn(clippy::inconsistent_digit_grouping)]
+#[deny(clippy::unreadable_literal)]
+#[allow(unused_variables, clippy::excessive_precision)]
+fn main() {
+    macro_rules! mac1 {
+        () => {
+            1_23_456
+        };
+    }
+    macro_rules! mac2 {
+        () => {
+            1_234.5678_f32
+        };
+    }
+
+    let good = (
+        123,
+        1_234,
+        1_2345_6789,
+        123_f32,
+        1_234.12_f32,
+        1_234.123_4_f32,
+        1.123_456_7_f32,
+    );
+    let bad = (123_456, 12_345_678, 1_234_567, 1_234.567_8_f32, 1.234_567_8_f32);
+
+    // Test padding
+    let _ = 0x0010_0000;
+    let _ = 0x0100_0000;
+    let _ = 0x1000_0000;
+    let _ = 0x0001_0000_0000_u64;
+
+    // Test suggestion when fraction has no digits
+    let _: f32 = 123_456.;
+
+    // Test UUID formatted literal
+    let _: u128 = 0x12345678_1234_1234_1234_123456789012;
+
+    // Ignore literals in macros
+    let _ = mac1!();
+    let _ = mac2!();
+}
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
new file mode 100644
index 00000000000..79ce38be19b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
@@ -0,0 +1,43 @@
+// run-rustfix
+#[warn(clippy::inconsistent_digit_grouping)]
+#[deny(clippy::unreadable_literal)]
+#[allow(unused_variables, clippy::excessive_precision)]
+fn main() {
+    macro_rules! mac1 {
+        () => {
+            1_23_456
+        };
+    }
+    macro_rules! mac2 {
+        () => {
+            1_234.5678_f32
+        };
+    }
+
+    let good = (
+        123,
+        1_234,
+        1_2345_6789,
+        123_f32,
+        1_234.12_f32,
+        1_234.123_4_f32,
+        1.123_456_7_f32,
+    );
+    let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+
+    // Test padding
+    let _ = 0x100000;
+    let _ = 0x1000000;
+    let _ = 0x10000000;
+    let _ = 0x100000000_u64;
+
+    // Test suggestion when fraction has no digits
+    let _: f32 = 1_23_456.;
+
+    // Test UUID formatted literal
+    let _: u128 = 0x12345678_1234_1234_1234_123456789012;
+
+    // Ignore literals in macros
+    let _ = mac1!();
+    let _ = mac2!();
+}
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr
new file mode 100644
index 00000000000..b8ac9155462
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr
@@ -0,0 +1,70 @@
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:26:16
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                ^^^^^^^^ help: consider: `123_456`
+   |
+   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:26:26
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                          ^^^^^^^^^^ help: consider: `12_345_678`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:26:38
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                      ^^^^^^^^ help: consider: `1_234_567`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:26:48
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                                ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:26:64
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                                                ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32`
+
+error: long literal lacking separators
+  --> $DIR/inconsistent_digit_grouping.rs:29:13
+   |
+LL |     let _ = 0x100000;
+   |             ^^^^^^^^ help: consider: `0x0010_0000`
+   |
+note: the lint level is defined here
+  --> $DIR/inconsistent_digit_grouping.rs:3:8
+   |
+LL | #[deny(clippy::unreadable_literal)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: long literal lacking separators
+  --> $DIR/inconsistent_digit_grouping.rs:30:13
+   |
+LL |     let _ = 0x1000000;
+   |             ^^^^^^^^^ help: consider: `0x0100_0000`
+
+error: long literal lacking separators
+  --> $DIR/inconsistent_digit_grouping.rs:31:13
+   |
+LL |     let _ = 0x10000000;
+   |             ^^^^^^^^^^ help: consider: `0x1000_0000`
+
+error: long literal lacking separators
+  --> $DIR/inconsistent_digit_grouping.rs:32:13
+   |
+LL |     let _ = 0x100000000_u64;
+   |             ^^^^^^^^^^^^^^^ help: consider: `0x0001_0000_0000_u64`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/inconsistent_digit_grouping.rs:35:18
+   |
+LL |     let _: f32 = 1_23_456.;
+   |                  ^^^^^^^^^ help: consider: `123_456.`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
new file mode 100644
index 00000000000..000d5269930
--- /dev/null
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::indexing_slicing)]
+// We also check the out_of_bounds_indexing lint here, because it lints similar things and
+// we want to avoid false positives.
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+fn main() {
+    let x = [1, 2, 3, 4];
+    let index: usize = 1;
+    x[index];
+    x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+    x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+
+    x[0]; // Ok, should not produce stderr.
+    x[3]; // Ok, should not produce stderr.
+
+    let y = &x;
+    y[0];
+
+    let v = vec![0; 5];
+    v[0];
+    v[10];
+    v[1 << 3];
+
+    const N: usize = 15; // Out of bounds
+    const M: usize = 3; // In bounds
+    x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+    x[M]; // Ok, should not produce stderr.
+    v[N];
+    v[M];
+}
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
new file mode 100644
index 00000000000..ac5f0d0a39e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -0,0 +1,79 @@
+error: this operation will panic at runtime
+  --> $DIR/indexing_slicing_index.rs:11:5
+   |
+LL |     x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^ index out of bounds: the len is 4 but the index is 4
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/indexing_slicing_index.rs:12:5
+   |
+LL |     x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^^^^^^ index out of bounds: the len is 4 but the index is 8
+
+error: this operation will panic at runtime
+  --> $DIR/indexing_slicing_index.rs:27:5
+   |
+LL |     x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^ index out of bounds: the len is 4 but the index is 15
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:10:5
+   |
+LL |     x[index];
+   |     ^^^^^^^^
+   |
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:18:5
+   |
+LL |     y[0];
+   |     ^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:21:5
+   |
+LL |     v[0];
+   |     ^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:22:5
+   |
+LL |     v[10];
+   |     ^^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:23:5
+   |
+LL |     v[1 << 3];
+   |     ^^^^^^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:29:5
+   |
+LL |     v[N];
+   |     ^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic.
+  --> $DIR/indexing_slicing_index.rs:30:5
+   |
+LL |     v[M];
+   |     ^^^^
+   |
+   = help: Consider using `.get(n)` or `.get_mut(n)` instead
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.rs b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs
new file mode 100644
index 00000000000..7b107db39f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs
@@ -0,0 +1,37 @@
+#![warn(clippy::indexing_slicing)]
+// We also check the out_of_bounds_indexing lint here, because it lints similar things and
+// we want to avoid false positives.
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+fn main() {
+    let x = [1, 2, 3, 4];
+    let index: usize = 1;
+    let index_from: usize = 2;
+    let index_to: usize = 3;
+    &x[index..];
+    &x[..index];
+    &x[index_from..index_to];
+    &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
+    &x[5..][..10]; // Two lint reports, one for out of bounds [5..] and another for slicing [..10].
+    &x[0..][..3];
+    &x[1..][..5];
+
+    &x[0..].get(..3); // Ok, should not produce stderr.
+    &x[0..3]; // Ok, should not produce stderr.
+
+    let y = &x;
+    &y[1..2];
+    &y[0..=4];
+    &y[..=4];
+
+    &y[..]; // Ok, should not produce stderr.
+
+    let v = vec![0; 5];
+    &v[10..100];
+    &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
+    &v[10..];
+    &v[..100];
+
+    &v[..]; // Ok, should not produce stderr.
+}
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr
new file mode 100644
index 00000000000..ec6c157ac1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr
@@ -0,0 +1,137 @@
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:12:6
+   |
+LL |     &x[index..];
+   |      ^^^^^^^^^^
+   |
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+   = help: Consider using `.get(n..)` or .get_mut(n..)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:13:6
+   |
+LL |     &x[..index];
+   |      ^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:14:6
+   |
+LL |     &x[index_from..index_to];
+   |      ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:15:6
+   |
+LL |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:15:6
+   |
+LL |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
+   |      ^^^^^^^^^^^^^^^
+   |
+   = help: Consider using `.get(n..)` or .get_mut(n..)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:16:6
+   |
+LL |     &x[5..][..10]; // Two lint reports, one for out of bounds [5..] and another for slicing [..10].
+   |      ^^^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: range is out of bounds
+  --> $DIR/indexing_slicing_slice.rs:16:8
+   |
+LL |     &x[5..][..10]; // Two lint reports, one for out of bounds [5..] and another for slicing [..10].
+   |        ^
+   |
+   = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:17:6
+   |
+LL |     &x[0..][..3];
+   |      ^^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:18:6
+   |
+LL |     &x[1..][..5];
+   |      ^^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:24:6
+   |
+LL |     &y[1..2];
+   |      ^^^^^^^
+   |
+   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:25:6
+   |
+LL |     &y[0..=4];
+   |      ^^^^^^^^
+   |
+   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:26:6
+   |
+LL |     &y[..=4];
+   |      ^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:31:6
+   |
+LL |     &v[10..100];
+   |      ^^^^^^^^^^
+   |
+   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:32:6
+   |
+LL |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
+   |      ^^^^^^^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: range is out of bounds
+  --> $DIR/indexing_slicing_slice.rs:32:8
+   |
+LL |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
+   |        ^^
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:33:6
+   |
+LL |     &v[10..];
+   |      ^^^^^^^
+   |
+   = help: Consider using `.get(n..)` or .get_mut(n..)` instead
+
+error: slicing may panic.
+  --> $DIR/indexing_slicing_slice.rs:34:6
+   |
+LL |     &v[..100];
+   |      ^^^^^^^^
+   |
+   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.fixed b/src/tools/clippy/tests/ui/inefficient_to_string.fixed
new file mode 100644
index 00000000000..c972b9419ef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inefficient_to_string.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+#![deny(clippy::inefficient_to_string)]
+
+use std::borrow::Cow;
+
+fn main() {
+    let rstr: &str = "hello";
+    let rrstr: &&str = &rstr;
+    let rrrstr: &&&str = &rrstr;
+    let _: String = rstr.to_string();
+    let _: String = (*rrstr).to_string();
+    let _: String = (**rrrstr).to_string();
+
+    let string: String = String::from("hello");
+    let rstring: &String = &string;
+    let rrstring: &&String = &rstring;
+    let rrrstring: &&&String = &rrstring;
+    let _: String = string.to_string();
+    let _: String = rstring.to_string();
+    let _: String = (*rrstring).to_string();
+    let _: String = (**rrrstring).to_string();
+
+    let cow: Cow<'_, str> = Cow::Borrowed("hello");
+    let rcow: &Cow<'_, str> = &cow;
+    let rrcow: &&Cow<'_, str> = &rcow;
+    let rrrcow: &&&Cow<'_, str> = &rrcow;
+    let _: String = cow.to_string();
+    let _: String = rcow.to_string();
+    let _: String = (*rrcow).to_string();
+    let _: String = (**rrrcow).to_string();
+}
diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.rs b/src/tools/clippy/tests/ui/inefficient_to_string.rs
new file mode 100644
index 00000000000..acdc55aa0d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inefficient_to_string.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+#![deny(clippy::inefficient_to_string)]
+
+use std::borrow::Cow;
+
+fn main() {
+    let rstr: &str = "hello";
+    let rrstr: &&str = &rstr;
+    let rrrstr: &&&str = &rrstr;
+    let _: String = rstr.to_string();
+    let _: String = rrstr.to_string();
+    let _: String = rrrstr.to_string();
+
+    let string: String = String::from("hello");
+    let rstring: &String = &string;
+    let rrstring: &&String = &rstring;
+    let rrrstring: &&&String = &rrstring;
+    let _: String = string.to_string();
+    let _: String = rstring.to_string();
+    let _: String = rrstring.to_string();
+    let _: String = rrrstring.to_string();
+
+    let cow: Cow<'_, str> = Cow::Borrowed("hello");
+    let rcow: &Cow<'_, str> = &cow;
+    let rrcow: &&Cow<'_, str> = &rcow;
+    let rrrcow: &&&Cow<'_, str> = &rrcow;
+    let _: String = cow.to_string();
+    let _: String = rcow.to_string();
+    let _: String = rrcow.to_string();
+    let _: String = rrrcow.to_string();
+}
diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.stderr b/src/tools/clippy/tests/ui/inefficient_to_string.stderr
new file mode 100644
index 00000000000..4be46161e8b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inefficient_to_string.stderr
@@ -0,0 +1,55 @@
+error: calling `to_string` on `&&str`
+  --> $DIR/inefficient_to_string.rs:11:21
+   |
+LL |     let _: String = rrstr.to_string();
+   |                     ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()`
+   |
+note: the lint level is defined here
+  --> $DIR/inefficient_to_string.rs:2:9
+   |
+LL | #![deny(clippy::inefficient_to_string)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString`
+
+error: calling `to_string` on `&&&str`
+  --> $DIR/inefficient_to_string.rs:12:21
+   |
+LL |     let _: String = rrrstr.to_string();
+   |                     ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstr).to_string()`
+   |
+   = help: `&&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString`
+
+error: calling `to_string` on `&&std::string::String`
+  --> $DIR/inefficient_to_string.rs:20:21
+   |
+LL |     let _: String = rrstring.to_string();
+   |                     ^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstring).to_string()`
+   |
+   = help: `&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString`
+
+error: calling `to_string` on `&&&std::string::String`
+  --> $DIR/inefficient_to_string.rs:21:21
+   |
+LL |     let _: String = rrrstring.to_string();
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstring).to_string()`
+   |
+   = help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString`
+
+error: calling `to_string` on `&&std::borrow::Cow<str>`
+  --> $DIR/inefficient_to_string.rs:29:21
+   |
+LL |     let _: String = rrcow.to_string();
+   |                     ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()`
+   |
+   = help: `&std::borrow::Cow<str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<str>` has a fast specialization of `ToString`
+
+error: calling `to_string` on `&&&std::borrow::Cow<str>`
+  --> $DIR/inefficient_to_string.rs:30:21
+   |
+LL |     let _: String = rrrcow.to_string();
+   |                     ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()`
+   |
+   = help: `&&std::borrow::Cow<str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<str>` has a fast specialization of `ToString`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed
new file mode 100644
index 00000000000..b8e40d99553
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed
@@ -0,0 +1,112 @@
+// run-rustfix
+#![feature(exhaustive_patterns, never_type)]
+#![allow(dead_code, unreachable_code, unused_variables)]
+#![allow(clippy::let_and_return)]
+
+enum SingleVariantEnum {
+    Variant(i32),
+}
+
+struct TupleStruct(i32);
+
+enum EmptyEnum {}
+
+macro_rules! match_enum {
+    ($param:expr) => {
+        let data = match $param {
+            SingleVariantEnum::Variant(i) => i,
+        };
+    };
+}
+
+fn infallible_destructuring_match_enum() {
+    let wrapper = SingleVariantEnum::Variant(0);
+
+    // This should lint!
+    let SingleVariantEnum::Variant(data) = wrapper;
+
+    // This shouldn't (inside macro)
+    match_enum!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(i) => -1,
+    };
+
+    let SingleVariantEnum::Variant(data) = wrapper;
+}
+
+macro_rules! match_struct {
+    ($param:expr) => {
+        let data = match $param {
+            TupleStruct(i) => i,
+        };
+    };
+}
+
+fn infallible_destructuring_match_struct() {
+    let wrapper = TupleStruct(0);
+
+    // This should lint!
+    let TupleStruct(data) = wrapper;
+
+    // This shouldn't (inside macro)
+    match_struct!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        TupleStruct(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        TupleStruct(i) => -1,
+    };
+
+    let TupleStruct(data) = wrapper;
+}
+
+macro_rules! match_never_enum {
+    ($param:expr) => {
+        let data = match $param {
+            Ok(i) => i,
+        };
+    };
+}
+
+fn never_enum() {
+    let wrapper: Result<i32, !> = Ok(23);
+
+    // This should lint!
+    let Ok(data) = wrapper;
+
+    // This shouldn't (inside macro)
+    match_never_enum!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        Ok(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        Ok(i) => -1,
+    };
+
+    let Ok(data) = wrapper;
+}
+
+impl EmptyEnum {
+    fn match_on(&self) -> ! {
+        // The lint shouldn't pick this up, as `let` won't work here!
+        let data = match *self {};
+        data
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs
new file mode 100644
index 00000000000..106cd438b90
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs
@@ -0,0 +1,118 @@
+// run-rustfix
+#![feature(exhaustive_patterns, never_type)]
+#![allow(dead_code, unreachable_code, unused_variables)]
+#![allow(clippy::let_and_return)]
+
+enum SingleVariantEnum {
+    Variant(i32),
+}
+
+struct TupleStruct(i32);
+
+enum EmptyEnum {}
+
+macro_rules! match_enum {
+    ($param:expr) => {
+        let data = match $param {
+            SingleVariantEnum::Variant(i) => i,
+        };
+    };
+}
+
+fn infallible_destructuring_match_enum() {
+    let wrapper = SingleVariantEnum::Variant(0);
+
+    // This should lint!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(i) => i,
+    };
+
+    // This shouldn't (inside macro)
+    match_enum!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(i) => -1,
+    };
+
+    let SingleVariantEnum::Variant(data) = wrapper;
+}
+
+macro_rules! match_struct {
+    ($param:expr) => {
+        let data = match $param {
+            TupleStruct(i) => i,
+        };
+    };
+}
+
+fn infallible_destructuring_match_struct() {
+    let wrapper = TupleStruct(0);
+
+    // This should lint!
+    let data = match wrapper {
+        TupleStruct(i) => i,
+    };
+
+    // This shouldn't (inside macro)
+    match_struct!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        TupleStruct(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        TupleStruct(i) => -1,
+    };
+
+    let TupleStruct(data) = wrapper;
+}
+
+macro_rules! match_never_enum {
+    ($param:expr) => {
+        let data = match $param {
+            Ok(i) => i,
+        };
+    };
+}
+
+fn never_enum() {
+    let wrapper: Result<i32, !> = Ok(23);
+
+    // This should lint!
+    let data = match wrapper {
+        Ok(i) => i,
+    };
+
+    // This shouldn't (inside macro)
+    match_never_enum!(wrapper);
+
+    // This shouldn't!
+    let data = match wrapper {
+        Ok(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        Ok(i) => -1,
+    };
+
+    let Ok(data) = wrapper;
+}
+
+impl EmptyEnum {
+    fn match_on(&self) -> ! {
+        // The lint shouldn't pick this up, as `let` won't work here!
+        let data = match *self {};
+        data
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr
new file mode 100644
index 00000000000..1b78db42014
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr
@@ -0,0 +1,28 @@
+error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let`
+  --> $DIR/infallible_destructuring_match.rs:26:5
+   |
+LL | /     let data = match wrapper {
+LL | |         SingleVariantEnum::Variant(i) => i,
+LL | |     };
+   | |______^ help: try this: `let SingleVariantEnum::Variant(data) = wrapper;`
+   |
+   = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings`
+
+error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let`
+  --> $DIR/infallible_destructuring_match.rs:58:5
+   |
+LL | /     let data = match wrapper {
+LL | |         TupleStruct(i) => i,
+LL | |     };
+   | |______^ help: try this: `let TupleStruct(data) = wrapper;`
+
+error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let`
+  --> $DIR/infallible_destructuring_match.rs:90:5
+   |
+LL | /     let data = match wrapper {
+LL | |         Ok(i) => i,
+LL | |     };
+   | |______^ help: try this: `let Ok(data) = wrapper;`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
new file mode 100644
index 00000000000..1fe68897765
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -0,0 +1,69 @@
+use std::iter::repeat;
+fn square_is_lower_64(x: &u32) -> bool {
+    x * x < 64
+}
+
+#[allow(clippy::maybe_infinite_iter)]
+#[deny(clippy::infinite_iter)]
+fn infinite_iters() {
+    repeat(0_u8).collect::<Vec<_>>(); // infinite iter
+    (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
+    (0..8_u64).chain(0..).max(); // infinite iter
+    (0_usize..)
+        .chain([0usize, 1, 2].iter().cloned())
+        .skip_while(|x| *x != 42)
+        .min(); // infinite iter
+    (0..8_u32)
+        .rev()
+        .cycle()
+        .map(|x| x + 1_u32)
+        .for_each(|x| println!("{}", x)); // infinite iter
+    (0..3_u32).flat_map(|x| x..).sum::<u32>(); // infinite iter
+    (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter
+    (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
+    (0..42_u64).by_ref().last(); // not an infinite, because ranges are double-ended
+    (0..).next(); // iterator is not exhausted
+}
+
+#[deny(clippy::maybe_infinite_iter)]
+fn potential_infinite_iters() {
+    (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
+    repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
+    (1..)
+        .scan(0, |state, x| {
+            *state += x;
+            Some(*state)
+        })
+        .min(); // maybe infinite iter
+    (0..).find(|x| *x == 24); // maybe infinite iter
+    (0..).position(|x| x == 24); // maybe infinite iter
+    (0..).any(|x| x == 24); // maybe infinite iter
+    (0..).all(|x| x == 24); // maybe infinite iter
+
+    (0..).zip(0..42).take_while(|&(x, _)| x != 42).count(); // not infinite
+    repeat(42).take_while(|x| *x == 42).next(); // iterator is not exhausted
+}
+
+fn main() {
+    infinite_iters();
+    potential_infinite_iters();
+}
+
+mod finite_collect {
+    use std::collections::HashSet;
+    use std::iter::FromIterator;
+
+    struct C;
+    impl FromIterator<i32> for C {
+        fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
+            C
+        }
+    }
+
+    fn check_collect() {
+        let _: HashSet<i32> = (0..).collect(); // Infinite iter
+
+        // Some data structures don't collect infinitely, such as `ArrayVec`
+        let _: C = (0..).collect();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr
new file mode 100644
index 00000000000..5f5e7ac9f25
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infinite_iter.stderr
@@ -0,0 +1,109 @@
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:9:5
+   |
+LL |     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/infinite_iter.rs:7:8
+   |
+LL | #[deny(clippy::infinite_iter)]
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:10:5
+   |
+LL |     (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:11:5
+   |
+LL |     (0..8_u64).chain(0..).max(); // infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:16:5
+   |
+LL | /     (0..8_u32)
+LL | |         .rev()
+LL | |         .cycle()
+LL | |         .map(|x| x + 1_u32)
+LL | |         .for_each(|x| println!("{}", x)); // infinite iter
+   | |________________________________________^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:22:5
+   |
+LL |     (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:23:5
+   |
+LL |     (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:30:5
+   |
+LL |     (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/infinite_iter.rs:28:8
+   |
+LL | #[deny(clippy::maybe_infinite_iter)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:31:5
+   |
+LL |     repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:32:5
+   |
+LL | /     (1..)
+LL | |         .scan(0, |state, x| {
+LL | |             *state += x;
+LL | |             Some(*state)
+LL | |         })
+LL | |         .min(); // maybe infinite iter
+   | |______________^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:38:5
+   |
+LL |     (0..).find(|x| *x == 24); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:39:5
+   |
+LL |     (0..).position(|x| x == 24); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:40:5
+   |
+LL |     (0..).any(|x| x == 24); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: possible infinite iteration detected
+  --> $DIR/infinite_iter.rs:41:5
+   |
+LL |     (0..).all(|x| x == 24); // maybe infinite iter
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:64:31
+   |
+LL |         let _: HashSet<i32> = (0..).collect(); // Infinite iter
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::infinite_iter)]` on by default
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infinite_loop.rs b/src/tools/clippy/tests/ui/infinite_loop.rs
new file mode 100644
index 00000000000..72591f12baf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infinite_loop.rs
@@ -0,0 +1,206 @@
+fn fn_val(i: i32) -> i32 {
+    unimplemented!()
+}
+fn fn_constref(i: &i32) -> i32 {
+    unimplemented!()
+}
+fn fn_mutref(i: &mut i32) {
+    unimplemented!()
+}
+fn fooi() -> i32 {
+    unimplemented!()
+}
+fn foob() -> bool {
+    unimplemented!()
+}
+
+#[allow(clippy::many_single_char_names)]
+fn immutable_condition() {
+    // Should warn when all vars mentioned are immutable
+    let y = 0;
+    while y < 10 {
+        println!("KO - y is immutable");
+    }
+
+    let x = 0;
+    while y < 10 && x < 3 {
+        let mut k = 1;
+        k += 2;
+        println!("KO - x and y immutable");
+    }
+
+    let cond = false;
+    while !cond {
+        println!("KO - cond immutable");
+    }
+
+    let mut i = 0;
+    while y < 10 && i < 3 {
+        i += 1;
+        println!("OK - i is mutable");
+    }
+
+    let mut mut_cond = false;
+    while !mut_cond || cond {
+        mut_cond = true;
+        println!("OK - mut_cond is mutable");
+    }
+
+    while fooi() < x {
+        println!("OK - Fn call results may vary");
+    }
+
+    while foob() {
+        println!("OK - Fn call results may vary");
+    }
+
+    let mut a = 0;
+    let mut c = move || {
+        while a < 5 {
+            a += 1;
+            println!("OK - a is mutable");
+        }
+    };
+    c();
+
+    let mut tup = (0, 0);
+    while tup.0 < 5 {
+        tup.0 += 1;
+        println!("OK - tup.0 gets mutated")
+    }
+}
+
+fn unused_var() {
+    // Should warn when a (mutable) var is not used in while body
+    let (mut i, mut j) = (0, 0);
+
+    while i < 3 {
+        j = 3;
+        println!("KO - i not mentioned");
+    }
+
+    while i < 3 && j > 0 {
+        println!("KO - i and j not mentioned");
+    }
+
+    while i < 3 {
+        let mut i = 5;
+        fn_mutref(&mut i);
+        println!("KO - shadowed");
+    }
+
+    while i < 3 && j > 0 {
+        i = 5;
+        println!("OK - i in cond and mentioned");
+    }
+}
+
+fn used_immutable() {
+    let mut i = 0;
+
+    while i < 3 {
+        fn_constref(&i);
+        println!("KO - const reference");
+    }
+
+    while i < 3 {
+        fn_val(i);
+        println!("KO - passed by value");
+    }
+
+    while i < 3 {
+        println!("OK - passed by mutable reference");
+        fn_mutref(&mut i)
+    }
+
+    while i < 3 {
+        fn_mutref(&mut i);
+        println!("OK - passed by mutable reference");
+    }
+}
+
+const N: i32 = 5;
+const B: bool = false;
+
+fn consts() {
+    while false {
+        println!("Constants are not linted");
+    }
+
+    while B {
+        println!("Constants are not linted");
+    }
+
+    while N > 0 {
+        println!("Constants are not linted");
+    }
+}
+
+use std::cell::Cell;
+
+fn maybe_i_mutate(i: &Cell<bool>) {
+    unimplemented!()
+}
+
+fn internally_mutable() {
+    let b = Cell::new(true);
+
+    while b.get() {
+        // b cannot be silently coerced to `bool`
+        maybe_i_mutate(&b);
+        println!("OK - Method call within condition");
+    }
+}
+
+struct Counter {
+    count: usize,
+}
+
+impl Counter {
+    fn inc(&mut self) {
+        self.count += 1;
+    }
+
+    fn inc_n(&mut self, n: usize) {
+        while self.count < n {
+            self.inc();
+        }
+        println!("OK - self borrowed mutably");
+    }
+
+    fn print_n(&self, n: usize) {
+        while self.count < n {
+            println!("KO - {} is not mutated", self.count);
+        }
+    }
+}
+
+fn while_loop_with_break_and_return() {
+    let y = 0;
+    while y < 10 {
+        if y == 0 {
+            break;
+        }
+        println!("KO - loop contains break");
+    }
+
+    while y < 10 {
+        if y == 0 {
+            return;
+        }
+        println!("KO - loop contains return");
+    }
+}
+
+fn main() {
+    immutable_condition();
+    unused_var();
+    used_immutable();
+    internally_mutable();
+
+    let mut c = Counter { count: 0 };
+    c.inc_n(5);
+    c.print_n(2);
+
+    while_loop_with_break_and_return();
+}
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
new file mode 100644
index 00000000000..1fcb29eff18
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -0,0 +1,95 @@
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:21:11
+   |
+LL |     while y < 10 {
+   |           ^^^^^^
+   |
+   = note: `#[deny(clippy::while_immutable_condition)]` on by default
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:26:11
+   |
+LL |     while y < 10 && x < 3 {
+   |           ^^^^^^^^^^^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:33:11
+   |
+LL |     while !cond {
+   |           ^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:77:11
+   |
+LL |     while i < 3 {
+   |           ^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:82:11
+   |
+LL |     while i < 3 && j > 0 {
+   |           ^^^^^^^^^^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:86:11
+   |
+LL |     while i < 3 {
+   |           ^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:101:11
+   |
+LL |     while i < 3 {
+   |           ^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:106:11
+   |
+LL |     while i < 3 {
+   |           ^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:172:15
+   |
+LL |         while self.count < n {
+   |               ^^^^^^^^^^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:180:11
+   |
+LL |     while y < 10 {
+   |           ^^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+   = note: this loop contains `return`s or `break`s
+   = help: rewrite it as `if cond { loop { } }`
+
+error: variables in the condition are not mutated in the loop body
+  --> $DIR/infinite_loop.rs:187:11
+   |
+LL |     while y < 10 {
+   |           ^^^^^^
+   |
+   = note: this may lead to an infinite or to a never running loop
+   = note: this loop contains `return`s or `break`s
+   = help: rewrite it as `if cond { loop { } }`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs
new file mode 100644
index 00000000000..e6cf337d1bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inherent_to_string.rs
@@ -0,0 +1,96 @@
+#![warn(clippy::inherent_to_string)]
+#![deny(clippy::inherent_to_string_shadow_display)]
+#![allow(clippy::many_single_char_names)]
+
+use std::fmt;
+
+trait FalsePositive {
+    fn to_string(&self) -> String;
+}
+
+struct A;
+struct B;
+struct C;
+struct D;
+struct E;
+struct F;
+
+impl A {
+    // Should be detected; emit warning
+    fn to_string(&self) -> String {
+        "A.to_string()".to_string()
+    }
+
+    // Should not be detected as it does not match the function signature
+    fn to_str(&self) -> String {
+        "A.to_str()".to_string()
+    }
+}
+
+// Should not be detected as it is a free function
+fn to_string() -> String {
+    "free to_string()".to_string()
+}
+
+impl B {
+    // Should not be detected, wrong return type
+    fn to_string(&self) -> i32 {
+        42
+    }
+}
+
+impl C {
+    // Should be detected and emit error as C also implements Display
+    fn to_string(&self) -> String {
+        "C.to_string()".to_string()
+    }
+}
+
+impl fmt::Display for C {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "impl Display for C")
+    }
+}
+
+impl FalsePositive for D {
+    // Should not be detected, as it is a trait function
+    fn to_string(&self) -> String {
+        "impl FalsePositive for D".to_string()
+    }
+}
+
+impl E {
+    // Should not be detected, as it is not bound to an instance
+    fn to_string() -> String {
+        "E::to_string()".to_string()
+    }
+}
+
+impl F {
+    // Should not be detected, as it does not match the function signature
+    fn to_string(&self, _i: i32) -> String {
+        "F.to_string()".to_string()
+    }
+}
+
+fn main() {
+    let a = A;
+    a.to_string();
+    a.to_str();
+
+    to_string();
+
+    let b = B;
+    b.to_string();
+
+    let c = C;
+    C.to_string();
+
+    let d = D;
+    d.to_string();
+
+    E::to_string();
+
+    let f = F;
+    f.to_string(1);
+}
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr
new file mode 100644
index 00000000000..4f331f5bec9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr
@@ -0,0 +1,28 @@
+error: implementation of inherent method `to_string(&self) -> String` for type `A`
+  --> $DIR/inherent_to_string.rs:20:5
+   |
+LL | /     fn to_string(&self) -> String {
+LL | |         "A.to_string()".to_string()
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::inherent-to-string` implied by `-D warnings`
+   = help: implement trait `Display` for type `A` instead
+
+error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
+  --> $DIR/inherent_to_string.rs:44:5
+   |
+LL | /     fn to_string(&self) -> String {
+LL | |         "C.to_string()".to_string()
+LL | |     }
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/inherent_to_string.rs:2:9
+   |
+LL | #![deny(clippy::inherent_to_string_shadow_display)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: remove the inherent method from type `C`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.fixed b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed
new file mode 100644
index 00000000000..fe21a71a42c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+
+#![warn(clippy::inline_fn_without_body)]
+#![allow(clippy::inline_always)]
+
+trait Foo {
+    fn default_inline();
+
+    fn always_inline();
+
+    fn never_inline();
+
+    #[inline]
+    fn has_body() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.rs b/src/tools/clippy/tests/ui/inline_fn_without_body.rs
new file mode 100644
index 00000000000..50746989466
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inline_fn_without_body.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#![warn(clippy::inline_fn_without_body)]
+#![allow(clippy::inline_always)]
+
+trait Foo {
+    #[inline]
+    fn default_inline();
+
+    #[inline(always)]
+    fn always_inline();
+
+    #[inline(never)]
+    fn never_inline();
+
+    #[inline]
+    fn has_body() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.stderr b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr
new file mode 100644
index 00000000000..32d35e209b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr
@@ -0,0 +1,28 @@
+error: use of `#[inline]` on trait method `default_inline` which has no body
+  --> $DIR/inline_fn_without_body.rs:7:5
+   |
+LL |       #[inline]
+   |  _____-^^^^^^^^
+LL | |     fn default_inline();
+   | |____- help: remove
+   |
+   = note: `-D clippy::inline-fn-without-body` implied by `-D warnings`
+
+error: use of `#[inline]` on trait method `always_inline` which has no body
+  --> $DIR/inline_fn_without_body.rs:10:5
+   |
+LL |       #[inline(always)]
+   |  _____-^^^^^^^^^^^^^^^^
+LL | |     fn always_inline();
+   | |____- help: remove
+
+error: use of `#[inline]` on trait method `never_inline` which has no body
+  --> $DIR/inline_fn_without_body.rs:13:5
+   |
+LL |       #[inline(never)]
+   |  _____-^^^^^^^^^^^^^^^
+LL | |     fn never_inline();
+   | |____- help: remove
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/int_plus_one.fixed b/src/tools/clippy/tests/ui/int_plus_one.fixed
new file mode 100644
index 00000000000..642830f24f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/int_plus_one.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+#[warn(clippy::int_plus_one)]
+fn main() {
+    let x = 1i32;
+    let y = 0i32;
+
+    let _ = x > y;
+    let _ = y < x;
+
+    let _ = x > y;
+    let _ = y < x;
+
+    let _ = x > y; // should be ok
+    let _ = y < x; // should be ok
+}
diff --git a/src/tools/clippy/tests/ui/int_plus_one.rs b/src/tools/clippy/tests/ui/int_plus_one.rs
new file mode 100644
index 00000000000..0755a0c79d2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/int_plus_one.rs
@@ -0,0 +1,17 @@
+// run-rustfix
+
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+#[warn(clippy::int_plus_one)]
+fn main() {
+    let x = 1i32;
+    let y = 0i32;
+
+    let _ = x >= y + 1;
+    let _ = y + 1 <= x;
+
+    let _ = x - 1 >= y;
+    let _ = y <= x - 1;
+
+    let _ = x > y; // should be ok
+    let _ = y < x; // should be ok
+}
diff --git a/src/tools/clippy/tests/ui/int_plus_one.stderr b/src/tools/clippy/tests/ui/int_plus_one.stderr
new file mode 100644
index 00000000000..29a6914761c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/int_plus_one.stderr
@@ -0,0 +1,28 @@
+error: Unnecessary `>= y + 1` or `x - 1 >=`
+  --> $DIR/int_plus_one.rs:9:13
+   |
+LL |     let _ = x >= y + 1;
+   |             ^^^^^^^^^^ help: change it to: `x > y`
+   |
+   = note: `-D clippy::int-plus-one` implied by `-D warnings`
+
+error: Unnecessary `>= y + 1` or `x - 1 >=`
+  --> $DIR/int_plus_one.rs:10:13
+   |
+LL |     let _ = y + 1 <= x;
+   |             ^^^^^^^^^^ help: change it to: `y < x`
+
+error: Unnecessary `>= y + 1` or `x - 1 >=`
+  --> $DIR/int_plus_one.rs:12:13
+   |
+LL |     let _ = x - 1 >= y;
+   |             ^^^^^^^^^^ help: change it to: `x > y`
+
+error: Unnecessary `>= y + 1` or `x - 1 >=`
+  --> $DIR/int_plus_one.rs:13:13
+   |
+LL |     let _ = y <= x - 1;
+   |             ^^^^^^^^^^ help: change it to: `y < x`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.rs b/src/tools/clippy/tests/ui/integer_arithmetic.rs
new file mode 100644
index 00000000000..7b1b64f390a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_arithmetic.rs
@@ -0,0 +1,99 @@
+#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::op_ref
+)]
+
+#[rustfmt::skip]
+fn main() {
+    let mut i = 1i32;
+    1 + i;
+    i * 2;
+    1 %
+    i / 2; // no error, this is part of the expression in the preceding line
+    i - 2 + 2 - i;
+    -i;
+    i >> 1;
+    i << 1;
+
+    // no error, overflows are checked by `overflowing_literals`
+    -1;
+    -(-1);
+
+    i & 1; // no wrapping
+    i | 1;
+    i ^ 1;
+
+    i += 1;
+    i -= 1;
+    i *= 2;
+    i /= 2;
+    i %= 2;
+    i <<= 3;
+    i >>= 2;
+
+    // no errors
+    i |= 1;
+    i &= 1;
+    i ^= i;
+
+    // No errors for the following items because they are constant expressions
+    enum Foo {
+        Bar = -2,
+    }
+    struct Baz([i32; 1 + 1]);
+    union Qux {
+        field: [i32; 1 + 1],
+    }
+    type Alias = [i32; 1 + 1];
+
+    const FOO: i32 = -2;
+    static BAR: i32 = -2;
+
+    let _: [i32; 1 + 1] = [0, 0];
+
+    let _: [i32; 1 + 1] = {
+        let a: [i32; 1 + 1] = [0, 0];
+        a
+    };
+
+    trait Trait {
+        const ASSOC: i32 = 1 + 1;
+    }
+
+    impl Trait for Foo {
+        const ASSOC: i32 = {
+            let _: [i32; 1 + 1];
+            fn foo() {}
+            1 + 1
+        };
+    }
+}
+
+// warn on references as well! (#5328)
+pub fn int_arith_ref() {
+    3 + &1;
+    &3 + 1;
+    &3 + &1;
+}
+
+pub fn foo(x: &i32) -> i32 {
+    let a = 5;
+    a + x
+}
+
+pub fn bar(x: &i32, y: &i32) -> i32 {
+    x + y
+}
+
+pub fn baz(x: i32, y: &i32) -> i32 {
+    x + y
+}
+
+pub fn qux(x: i32, y: i32) -> i32 {
+    (&x + &y)
+}
diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.stderr b/src/tools/clippy/tests/ui/integer_arithmetic.stderr
new file mode 100644
index 00000000000..83e8a9cde3f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_arithmetic.stderr
@@ -0,0 +1,131 @@
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:14:5
+   |
+LL |     1 + i;
+   |     ^^^^^
+   |
+   = note: `-D clippy::integer-arithmetic` implied by `-D warnings`
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:15:5
+   |
+LL |     i * 2;
+   |     ^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:16:5
+   |
+LL | /     1 %
+LL | |     i / 2; // no error, this is part of the expression in the preceding line
+   | |_________^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:18:5
+   |
+LL |     i - 2 + 2 - i;
+   |     ^^^^^^^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:19:5
+   |
+LL |     -i;
+   |     ^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:20:5
+   |
+LL |     i >> 1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:21:5
+   |
+LL |     i << 1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:31:5
+   |
+LL |     i += 1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:32:5
+   |
+LL |     i -= 1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:33:5
+   |
+LL |     i *= 2;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:34:5
+   |
+LL |     i /= 2;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:35:5
+   |
+LL |     i %= 2;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:36:5
+   |
+LL |     i <<= 3;
+   |     ^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:37:5
+   |
+LL |     i >>= 2;
+   |     ^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:79:5
+   |
+LL |     3 + &1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:80:5
+   |
+LL |     &3 + 1;
+   |     ^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:81:5
+   |
+LL |     &3 + &1;
+   |     ^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:86:5
+   |
+LL |     a + x
+   |     ^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:90:5
+   |
+LL |     x + y
+   |     ^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:94:5
+   |
+LL |     x + y
+   |     ^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:98:5
+   |
+LL |     (&x + &y)
+   |     ^^^^^^^^^
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/integer_division.rs b/src/tools/clippy/tests/ui/integer_division.rs
new file mode 100644
index 00000000000..800c7525752
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_division.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::integer_division)]
+
+fn main() {
+    let two = 2;
+    let n = 1 / 2;
+    let o = 1 / two;
+    let p = two / 4;
+    let x = 1. / 2.0;
+}
diff --git a/src/tools/clippy/tests/ui/integer_division.stderr b/src/tools/clippy/tests/ui/integer_division.stderr
new file mode 100644
index 00000000000..72a232ef3d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_division.stderr
@@ -0,0 +1,27 @@
+error: integer division
+  --> $DIR/integer_division.rs:5:13
+   |
+LL |     let n = 1 / 2;
+   |             ^^^^^
+   |
+   = note: `-D clippy::integer-division` implied by `-D warnings`
+   = help: division of integers may cause loss of precision. consider using floats.
+
+error: integer division
+  --> $DIR/integer_division.rs:6:13
+   |
+LL |     let o = 1 / two;
+   |             ^^^^^^^
+   |
+   = help: division of integers may cause loss of precision. consider using floats.
+
+error: integer division
+  --> $DIR/integer_division.rs:7:13
+   |
+LL |     let p = two / 4;
+   |             ^^^^^^^
+   |
+   = help: division of integers may cause loss of precision. consider using floats.
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
new file mode 100644
index 00000000000..c30d23de3f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
@@ -0,0 +1,43 @@
+// run-rustfix
+#![allow(clippy::useless_vec)]
+#![warn(clippy::into_iter_on_ref)]
+
+struct X;
+use std::collections::*;
+
+fn main() {
+    for _ in &[1, 2, 3] {}
+    for _ in vec![X, X] {}
+    for _ in &vec![X, X] {}
+
+    let _ = vec![1, 2, 3].into_iter();
+    let _ = (&vec![1, 2, 3]).iter(); //~ WARN equivalent to .iter()
+    let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ WARN equivalent to .iter()
+    let _ = std::rc::Rc::from(&[X][..]).iter(); //~ WARN equivalent to .iter()
+    let _ = std::sync::Arc::from(&[X][..]).iter(); //~ WARN equivalent to .iter()
+
+    let _ = (&&&&&&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter()
+    let _ = (&&&&mut &&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter()
+    let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); //~ ERROR equivalent to .iter_mut()
+
+    let _ = (&Some(4)).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Some(5)).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Ok::<_, i32>(6)).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Err::<i32, _>(7)).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Vec::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Vec::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&BTreeMap::<i32, u64>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut BTreeMap::<i32, u64>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&VecDeque::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut VecDeque::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&LinkedList::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut LinkedList::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&HashMap::<i32, u64>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut HashMap::<i32, u64>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+
+    let _ = (&BTreeSet::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&BinaryHeap::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    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()
+}
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
new file mode 100644
index 00000000000..94bc1689619
--- /dev/null
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
@@ -0,0 +1,43 @@
+// run-rustfix
+#![allow(clippy::useless_vec)]
+#![warn(clippy::into_iter_on_ref)]
+
+struct X;
+use std::collections::*;
+
+fn main() {
+    for _ in &[1, 2, 3] {}
+    for _ in vec![X, X] {}
+    for _ in &vec![X, X] {}
+
+    let _ = vec![1, 2, 3].into_iter();
+    let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
+    let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+
+    let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+    let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+    let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
+
+    let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+
+    let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    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()
+}
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
new file mode 100644
index 00000000000..80e2d104f82
--- /dev/null
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
@@ -0,0 +1,160 @@
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+  --> $DIR/into_iter_on_ref.rs:14:30
+   |
+LL |     let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
+   |                              ^^^^^^^^^ help: call directly: `iter`
+   |
+   = note: `-D clippy::into-iter-on-ref` implied by `-D warnings`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+  --> $DIR/into_iter_on_ref.rs:15:46
+   |
+LL |     let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
+   |                                              ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+  --> $DIR/into_iter_on_ref.rs:16:41
+   |
+LL |     let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+  --> $DIR/into_iter_on_ref.rs:17:44
+   |
+LL |     let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+   |                                            ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+  --> $DIR/into_iter_on_ref.rs:19:32
+   |
+LL |     let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+   |                                ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+  --> $DIR/into_iter_on_ref.rs:20:36
+   |
+LL |     let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+   |                                    ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `array`
+  --> $DIR/into_iter_on_ref.rs:21:40
+   |
+LL |     let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
+   |                                        ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Option`
+  --> $DIR/into_iter_on_ref.rs:23:24
+   |
+LL |     let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
+   |                        ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Option`
+  --> $DIR/into_iter_on_ref.rs:24:28
+   |
+LL |     let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                            ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Result`
+  --> $DIR/into_iter_on_ref.rs:25:32
+   |
+LL |     let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
+   |                                ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Result`
+  --> $DIR/into_iter_on_ref.rs:26:37
+   |
+LL |     let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                     ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+  --> $DIR/into_iter_on_ref.rs:27:34
+   |
+LL |     let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                  ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Vec`
+  --> $DIR/into_iter_on_ref.rs:28:38
+   |
+LL |     let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                      ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeMap`
+  --> $DIR/into_iter_on_ref.rs:29:44
+   |
+LL |     let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                            ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `BTreeMap`
+  --> $DIR/into_iter_on_ref.rs:30:48
+   |
+LL |     let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                                ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `VecDeque`
+  --> $DIR/into_iter_on_ref.rs:31:39
+   |
+LL |     let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                       ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `VecDeque`
+  --> $DIR/into_iter_on_ref.rs:32:43
+   |
+LL |     let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                           ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `LinkedList`
+  --> $DIR/into_iter_on_ref.rs:33:41
+   |
+LL |     let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `LinkedList`
+  --> $DIR/into_iter_on_ref.rs:34:45
+   |
+LL |     let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                             ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashMap`
+  --> $DIR/into_iter_on_ref.rs:35:43
+   |
+LL |     let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                           ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `HashMap`
+  --> $DIR/into_iter_on_ref.rs:36:47
+   |
+LL |     let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                               ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeSet`
+  --> $DIR/into_iter_on_ref.rs:38:39
+   |
+LL |     let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                       ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BinaryHeap`
+  --> $DIR/into_iter_on_ref.rs:39:41
+   |
+LL |     let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashSet`
+  --> $DIR/into_iter_on_ref.rs:40:38
+   |
+LL |     let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                      ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Path`
+  --> $DIR/into_iter_on_ref.rs:41:43
+   |
+LL |     let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
+   |                                           ^^^^^^^^^ help: call directly: `iter`
+
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `PathBuf`
+  --> $DIR/into_iter_on_ref.rs:42:47
+   |
+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
+
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
new file mode 100644
index 00000000000..697416dcee8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs
@@ -0,0 +1,85 @@
+#![warn(clippy::invalid_upcast_comparisons)]
+#![allow(
+    unused,
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::cast_lossless
+)]
+
+fn mk_value<T>() -> T {
+    unimplemented!()
+}
+
+fn main() {
+    let u32: u32 = mk_value();
+    let u8: u8 = mk_value();
+    let i32: i32 = mk_value();
+    let i8: i8 = mk_value();
+
+    // always false, since no u8 can be > 300
+    (u8 as u32) > 300;
+    (u8 as i32) > 300;
+    (u8 as u32) == 300;
+    (u8 as i32) == 300;
+    300 < (u8 as u32);
+    300 < (u8 as i32);
+    300 == (u8 as u32);
+    300 == (u8 as i32);
+    // inverted of the above
+    (u8 as u32) <= 300;
+    (u8 as i32) <= 300;
+    (u8 as u32) != 300;
+    (u8 as i32) != 300;
+    300 >= (u8 as u32);
+    300 >= (u8 as i32);
+    300 != (u8 as u32);
+    300 != (u8 as i32);
+
+    // always false, since u8 -> i32 doesn't wrap
+    (u8 as i32) < 0;
+    -5 != (u8 as i32);
+    // inverted of the above
+    (u8 as i32) >= 0;
+    -5 == (u8 as i32);
+
+    // always false, since no u8 can be 1337
+    1337 == (u8 as i32);
+    1337 == (u8 as u32);
+    // inverted of the above
+    1337 != (u8 as i32);
+    1337 != (u8 as u32);
+
+    // Those are Ok:
+    (u8 as u32) > 20;
+    42 == (u8 as i32);
+    42 != (u8 as i32);
+    42 > (u8 as i32);
+    (u8 as i32) == 42;
+    (u8 as i32) != 42;
+    (u8 as i32) > 42;
+    (u8 as i32) < 42;
+
+    (u8 as i8) == -1;
+    (u8 as i8) != -1;
+    (u8 as i32) > -1;
+    (u8 as i32) < -1;
+    (u32 as i32) < -5;
+    (u32 as i32) < 10;
+
+    (i8 as u8) == 1;
+    (i8 as u8) != 1;
+    (i8 as u8) < 1;
+    (i8 as u8) > 1;
+    (i32 as u32) < 5;
+    (i32 as u32) < 10;
+
+    -5 < (u32 as i32);
+    0 <= (u32 as i32);
+    0 < (u32 as i32);
+
+    -5 > (u32 as i32);
+    -5 >= (u8 as i32);
+
+    -5 == (u32 as i32);
+}
diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
new file mode 100644
index 00000000000..03c3fb80aaa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr
@@ -0,0 +1,166 @@
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:21:5
+   |
+LL |     (u8 as u32) > 300;
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings`
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:22:5
+   |
+LL |     (u8 as i32) > 300;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:23:5
+   |
+LL |     (u8 as u32) == 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:24:5
+   |
+LL |     (u8 as i32) == 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:25:5
+   |
+LL |     300 < (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:26:5
+   |
+LL |     300 < (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:27:5
+   |
+LL |     300 == (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:28:5
+   |
+LL |     300 == (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:30:5
+   |
+LL |     (u8 as u32) <= 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:31:5
+   |
+LL |     (u8 as i32) <= 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:32:5
+   |
+LL |     (u8 as u32) != 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:33:5
+   |
+LL |     (u8 as i32) != 300;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:34:5
+   |
+LL |     300 >= (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:35:5
+   |
+LL |     300 >= (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:36:5
+   |
+LL |     300 != (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:37:5
+   |
+LL |     300 != (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:40:5
+   |
+LL |     (u8 as i32) < 0;
+   |     ^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:41:5
+   |
+LL |     -5 != (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:43:5
+   |
+LL |     (u8 as i32) >= 0;
+   |     ^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:44:5
+   |
+LL |     -5 == (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:47:5
+   |
+LL |     1337 == (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:48:5
+   |
+LL |     1337 == (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:50:5
+   |
+LL |     1337 != (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:51:5
+   |
+LL |     1337 != (u8 as u32);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always true
+  --> $DIR/invalid_upcast_comparisons.rs:65:5
+   |
+LL |     (u8 as i32) > -1;
+   |     ^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:66:5
+   |
+LL |     (u8 as i32) < -1;
+   |     ^^^^^^^^^^^^^^^^
+
+error: because of the numeric bounds on `u8` prior to casting, this expression is always false
+  --> $DIR/invalid_upcast_comparisons.rs:82:5
+   |
+LL |     -5 >= (u8 as i32);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 27 previous errors
+
diff --git a/src/tools/clippy/tests/ui/issue-3145.rs b/src/tools/clippy/tests/ui/issue-3145.rs
new file mode 100644
index 00000000000..f497d5550af
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue-3145.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("{}" a); //~ERROR expected token: `,`
+}
diff --git a/src/tools/clippy/tests/ui/issue-3145.stderr b/src/tools/clippy/tests/ui/issue-3145.stderr
new file mode 100644
index 00000000000..cb0d95f5e26
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue-3145.stderr
@@ -0,0 +1,8 @@
+error: expected token: `,`
+  --> $DIR/issue-3145.rs:2:19
+   |
+LL |     println!("{}" a); //~ERROR expected token: `,`
+   |                   ^ expected `,`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/issue-3746.rs b/src/tools/clippy/tests/ui/issue-3746.rs
new file mode 100644
index 00000000000..879d1d5d916
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue-3746.rs
@@ -0,0 +1,22 @@
+// ignore-macos
+// ignore-windows
+
+#![warn(clippy::empty_loop)]
+#![feature(lang_items, link_args, start, libc)]
+#![link_args = "-nostartfiles"]
+#![no_std]
+
+use core::panic::PanicInfo;
+
+#[start]
+fn main(argc: isize, argv: *const *const u8) -> isize {
+    loop {}
+}
+
+#[panic_handler]
+fn panic(_info: &PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/issue_2356.rs b/src/tools/clippy/tests/ui/issue_2356.rs
new file mode 100644
index 00000000000..da580a1839a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue_2356.rs
@@ -0,0 +1,24 @@
+#![deny(clippy::while_let_on_iterator)]
+
+use std::iter::Iterator;
+
+struct Foo;
+
+impl Foo {
+    fn foo1<I: Iterator<Item = usize>>(mut it: I) {
+        while let Some(_) = it.next() {
+            println!("{:?}", it.size_hint());
+        }
+    }
+
+    fn foo2<I: Iterator<Item = usize>>(mut it: I) {
+        while let Some(e) = it.next() {
+            println!("{:?}", e);
+        }
+    }
+}
+
+fn main() {
+    Foo::foo1(vec![].into_iter());
+    Foo::foo2(vec![].into_iter());
+}
diff --git a/src/tools/clippy/tests/ui/issue_2356.stderr b/src/tools/clippy/tests/ui/issue_2356.stderr
new file mode 100644
index 00000000000..51b872e21c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue_2356.stderr
@@ -0,0 +1,14 @@
+error: this loop could be written as a `for` loop
+  --> $DIR/issue_2356.rs:15:9
+   |
+LL |         while let Some(e) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it`
+   |
+note: the lint level is defined here
+  --> $DIR/issue_2356.rs:1:9
+   |
+LL | #![deny(clippy::while_let_on_iterator)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/issue_4266.rs b/src/tools/clippy/tests/ui/issue_4266.rs
new file mode 100644
index 00000000000..8a9d5a3d1d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue_4266.rs
@@ -0,0 +1,37 @@
+// edition:2018
+#![allow(dead_code)]
+
+async fn sink1<'a>(_: &'a str) {} // lint
+async fn sink1_elided(_: &str) {} // ok
+
+// lint
+async fn one_to_one<'a>(s: &'a str) -> &'a str {
+    s
+}
+
+// ok
+async fn one_to_one_elided(s: &str) -> &str {
+    s
+}
+
+// ok
+async fn all_to_one<'a>(a: &'a str, _b: &'a str) -> &'a str {
+    a
+}
+
+// async fn unrelated(_: &str, _: &str) {} // Not allowed in async fn
+
+// #3988
+struct Foo;
+impl Foo {
+    // ok
+    pub async fn foo(&mut self) {}
+}
+
+// rust-lang/rust#61115
+// ok
+async fn print(s: &str) {
+    println!("{}", s);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr
new file mode 100644
index 00000000000..0426508e622
--- /dev/null
+++ b/src/tools/clippy/tests/ui/issue_4266.stderr
@@ -0,0 +1,16 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/issue_4266.rs:4:1
+   |
+LL | async fn sink1<'a>(_: &'a str) {} // lint
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/issue_4266.rs:8:1
+   |
+LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/item_after_statement.rs b/src/tools/clippy/tests/ui/item_after_statement.rs
new file mode 100644
index 00000000000..c17a7cbc8d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/item_after_statement.rs
@@ -0,0 +1,36 @@
+#![warn(clippy::items_after_statements)]
+
+fn ok() {
+    fn foo() {
+        println!("foo");
+    }
+    foo();
+}
+
+fn last() {
+    foo();
+    fn foo() {
+        println!("foo");
+    }
+}
+
+fn main() {
+    foo();
+    fn foo() {
+        println!("foo");
+    }
+    foo();
+}
+
+fn mac() {
+    let mut a = 5;
+    println!("{}", a);
+    // do not lint this, because it needs to be after `a`
+    macro_rules! b {
+        () => {{
+            a = 6
+        }};
+    }
+    b!();
+    println!("{}", a);
+}
diff --git a/src/tools/clippy/tests/ui/item_after_statement.stderr b/src/tools/clippy/tests/ui/item_after_statement.stderr
new file mode 100644
index 00000000000..f8f010b5e5c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/item_after_statement.stderr
@@ -0,0 +1,20 @@
+error: adding items after statements is confusing, since items exist from the start of the scope
+  --> $DIR/item_after_statement.rs:12:5
+   |
+LL | /     fn foo() {
+LL | |         println!("foo");
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::items-after-statements` implied by `-D warnings`
+
+error: adding items after statements is confusing, since items exist from the start of the scope
+  --> $DIR/item_after_statement.rs:19:5
+   |
+LL | /     fn foo() {
+LL | |         println!("foo");
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
new file mode 100644
index 00000000000..2773227e26b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![allow(unused)]
+
+use std::collections::HashSet;
+use std::collections::VecDeque;
+
+fn main() {
+    let v = [1, 2, 3, 4, 5];
+    let v2: Vec<isize> = v.to_vec();
+    let v3: HashSet<isize> = v.iter().cloned().collect();
+    let v4: VecDeque<isize> = v.iter().cloned().collect();
+
+    // Handle macro expansion in suggestion
+    let _: Vec<isize> = vec![1, 2, 3].to_vec();
+
+    // Issue #3704
+    unsafe {
+        let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
+            .to_bytes().to_vec();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
new file mode 100644
index 00000000000..60a4eac23c7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+
+#![allow(unused)]
+
+use std::collections::HashSet;
+use std::collections::VecDeque;
+
+fn main() {
+    let v = [1, 2, 3, 4, 5];
+    let v2: Vec<isize> = v.iter().cloned().collect();
+    let v3: HashSet<isize> = v.iter().cloned().collect();
+    let v4: VecDeque<isize> = v.iter().cloned().collect();
+
+    // Handle macro expansion in suggestion
+    let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
+
+    // Issue #3704
+    unsafe {
+        let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
+            .to_bytes()
+            .iter()
+            .cloned()
+            .collect();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
new file mode 100644
index 00000000000..b90a1e6c919
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
@@ -0,0 +1,26 @@
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/iter_cloned_collect.rs:10:27
+   |
+LL |     let v2: Vec<isize> = v.iter().cloned().collect();
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+   |
+   = note: `-D clippy::iter-cloned-collect` implied by `-D warnings`
+
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/iter_cloned_collect.rs:15:38
+   |
+LL |     let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/iter_cloned_collect.rs:20:24
+   |
+LL |               .to_bytes()
+   |  ________________________^
+LL | |             .iter()
+LL | |             .cloned()
+LL | |             .collect();
+   | |______________________^ help: try: `.to_vec()`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_nth.rs b/src/tools/clippy/tests/ui/iter_nth.rs
new file mode 100644
index 00000000000..9c21dd82ee4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth.rs
@@ -0,0 +1,56 @@
+// aux-build:option_helpers.rs
+
+#![warn(clippy::iter_nth)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+use std::collections::VecDeque;
+
+/// Struct to generate false positives for things with `.iter()`.
+#[derive(Copy, Clone)]
+struct HasIter;
+
+impl HasIter {
+    fn iter(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+
+    fn iter_mut(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+}
+
+/// Checks implementation of `ITER_NTH` lint.
+fn iter_nth() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
+
+    {
+        // Make sure we lint `.iter()` for relevant types.
+        let bad_vec = some_vec.iter().nth(3);
+        let bad_slice = &some_vec[..].iter().nth(3);
+        let bad_boxed_slice = boxed_slice.iter().nth(3);
+        let bad_vec_deque = some_vec_deque.iter().nth(3);
+    }
+
+    {
+        // Make sure we lint `.iter_mut()` for relevant types.
+        let bad_vec = some_vec.iter_mut().nth(3);
+    }
+    {
+        let bad_slice = &some_vec[..].iter_mut().nth(3);
+    }
+    {
+        let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
+    }
+
+    // Make sure we don't lint for non-relevant types.
+    let false_positive = HasIter;
+    let ok = false_positive.iter().nth(3);
+    let ok_mut = false_positive.iter_mut().nth(3);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_nth.stderr b/src/tools/clippy/tests/ui/iter_nth.stderr
new file mode 100644
index 00000000000..d00b2fb672b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth.stderr
@@ -0,0 +1,59 @@
+error: called `.iter().nth()` on a Vec
+  --> $DIR/iter_nth.rs:33:23
+   |
+LL |         let bad_vec = some_vec.iter().nth(3);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-nth` implied by `-D warnings`
+   = help: calling `.get()` is both faster and more readable
+
+error: called `.iter().nth()` on a slice
+  --> $DIR/iter_nth.rs:34:26
+   |
+LL |         let bad_slice = &some_vec[..].iter().nth(3);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get()` is both faster and more readable
+
+error: called `.iter().nth()` on a slice
+  --> $DIR/iter_nth.rs:35:31
+   |
+LL |         let bad_boxed_slice = boxed_slice.iter().nth(3);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get()` is both faster and more readable
+
+error: called `.iter().nth()` on a VecDeque
+  --> $DIR/iter_nth.rs:36:29
+   |
+LL |         let bad_vec_deque = some_vec_deque.iter().nth(3);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get()` is both faster and more readable
+
+error: called `.iter_mut().nth()` on a Vec
+  --> $DIR/iter_nth.rs:41:23
+   |
+LL |         let bad_vec = some_vec.iter_mut().nth(3);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get_mut()` is both faster and more readable
+
+error: called `.iter_mut().nth()` on a slice
+  --> $DIR/iter_nth.rs:44:26
+   |
+LL |         let bad_slice = &some_vec[..].iter_mut().nth(3);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get_mut()` is both faster and more readable
+
+error: called `.iter_mut().nth()` on a VecDeque
+  --> $DIR/iter_nth.rs:47:29
+   |
+LL |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: calling `.get_mut()` is both faster and more readable
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.fixed b/src/tools/clippy/tests/ui/iter_nth_zero.fixed
new file mode 100644
index 00000000000..b54147c94d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth_zero.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![warn(clippy::iter_nth_zero)]
+use std::collections::HashSet;
+
+struct Foo {}
+
+impl Foo {
+    fn nth(&self, index: usize) -> usize {
+        index + 1
+    }
+}
+
+fn main() {
+    let f = Foo {};
+    f.nth(0); // lint does not apply here
+
+    let mut s = HashSet::new();
+    s.insert(1);
+    let _x = s.iter().next();
+
+    let mut s2 = HashSet::new();
+    s2.insert(2);
+    let mut iter = s2.iter();
+    let _y = iter.next();
+
+    let mut s3 = HashSet::new();
+    s3.insert(3);
+    let mut iter2 = s3.iter();
+    let _unwrapped = iter2.next().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.rs b/src/tools/clippy/tests/ui/iter_nth_zero.rs
new file mode 100644
index 00000000000..b92c7d18adb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth_zero.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![warn(clippy::iter_nth_zero)]
+use std::collections::HashSet;
+
+struct Foo {}
+
+impl Foo {
+    fn nth(&self, index: usize) -> usize {
+        index + 1
+    }
+}
+
+fn main() {
+    let f = Foo {};
+    f.nth(0); // lint does not apply here
+
+    let mut s = HashSet::new();
+    s.insert(1);
+    let _x = s.iter().nth(0);
+
+    let mut s2 = HashSet::new();
+    s2.insert(2);
+    let mut iter = s2.iter();
+    let _y = iter.nth(0);
+
+    let mut s3 = HashSet::new();
+    s3.insert(3);
+    let mut iter2 = s3.iter();
+    let _unwrapped = iter2.nth(0).unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.stderr b/src/tools/clippy/tests/ui/iter_nth_zero.stderr
new file mode 100644
index 00000000000..2b20a4ceb4a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth_zero.stderr
@@ -0,0 +1,22 @@
+error: called `.nth(0)` on a `std::iter::Iterator`
+  --> $DIR/iter_nth_zero.rs:20:14
+   |
+LL |     let _x = s.iter().nth(0);
+   |              ^^^^^^^^^^^^^^^ help: try calling: `s.iter().next()`
+   |
+   = note: `-D clippy::iter-nth-zero` implied by `-D warnings`
+
+error: called `.nth(0)` on a `std::iter::Iterator`
+  --> $DIR/iter_nth_zero.rs:25:14
+   |
+LL |     let _y = iter.nth(0);
+   |              ^^^^^^^^^^^ help: try calling: `iter.next()`
+
+error: called `.nth(0)` on a `std::iter::Iterator`
+  --> $DIR/iter_nth_zero.rs:30:22
+   |
+LL |     let _unwrapped = iter2.nth(0).unwrap();
+   |                      ^^^^^^^^^^^^ help: try calling: `iter2.next()`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs
new file mode 100644
index 00000000000..a65ca3bbb13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_next.rs
@@ -0,0 +1,22 @@
+// aux-build:option_helpers.rs
+
+#![warn(clippy::iter_skip_next)]
+#![allow(clippy::blacklisted_name)]
+
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+
+/// Checks implementation of `ITER_SKIP_NEXT` lint
+fn iter_skip_next() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let _ = some_vec.iter().skip(42).next();
+    let _ = some_vec.iter().cycle().skip(42).next();
+    let _ = (1..10).skip(10).next();
+    let _ = &some_vec[..].iter().skip(3).next();
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.skip(42).next();
+    let _ = foo.filter().skip(42).next();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr
new file mode 100644
index 00000000000..5709f335529
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr
@@ -0,0 +1,35 @@
+error: called `skip(x).next()` on an iterator
+  --> $DIR/iter_skip_next.rs:13:13
+   |
+LL |     let _ = some_vec.iter().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
+   = help: this is more succinctly expressed by calling `nth(x)`
+
+error: called `skip(x).next()` on an iterator
+  --> $DIR/iter_skip_next.rs:14:13
+   |
+LL |     let _ = some_vec.iter().cycle().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this is more succinctly expressed by calling `nth(x)`
+
+error: called `skip(x).next()` on an iterator
+  --> $DIR/iter_skip_next.rs:15:13
+   |
+LL |     let _ = (1..10).skip(10).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this is more succinctly expressed by calling `nth(x)`
+
+error: called `skip(x).next()` on an iterator
+  --> $DIR/iter_skip_next.rs:16:14
+   |
+LL |     let _ = &some_vec[..].iter().skip(3).next();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this is more succinctly expressed by calling `nth(x)`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iterator_step_by_zero.rs b/src/tools/clippy/tests/ui/iterator_step_by_zero.rs
new file mode 100644
index 00000000000..13d1cfd4281
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iterator_step_by_zero.rs
@@ -0,0 +1,28 @@
+#[warn(clippy::iterator_step_by_zero)]
+fn main() {
+    let _ = vec!["A", "B", "B"].iter().step_by(0);
+    let _ = "XXX".chars().step_by(0);
+    let _ = (0..1).step_by(0);
+
+    // No error, not an iterator.
+    let y = NotIterator;
+    y.step_by(0);
+
+    // No warning for non-zero step
+    let _ = (0..1).step_by(1);
+
+    let _ = (1..).step_by(0);
+    let _ = (1..=2).step_by(0);
+
+    let x = 0..1;
+    let _ = x.step_by(0);
+
+    // check const eval
+    let v1 = vec![1, 2, 3];
+    let _ = v1.iter().step_by(2 / 3);
+}
+
+struct NotIterator;
+impl NotIterator {
+    fn step_by(&self, _: u32) {}
+}
diff --git a/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr
new file mode 100644
index 00000000000..c2c6803b3e6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr
@@ -0,0 +1,46 @@
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:3:13
+   |
+LL |     let _ = vec!["A", "B", "B"].iter().step_by(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings`
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:4:13
+   |
+LL |     let _ = "XXX".chars().step_by(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:5:13
+   |
+LL |     let _ = (0..1).step_by(0);
+   |             ^^^^^^^^^^^^^^^^^
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:14:13
+   |
+LL |     let _ = (1..).step_by(0);
+   |             ^^^^^^^^^^^^^^^^
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:15:13
+   |
+LL |     let _ = (1..=2).step_by(0);
+   |             ^^^^^^^^^^^^^^^^^^
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:18:13
+   |
+LL |     let _ = x.step_by(0);
+   |             ^^^^^^^^^^^^
+
+error: Iterator::step_by(0) will panic at runtime
+  --> $DIR/iterator_step_by_zero.rs:22:13
+   |
+LL |     let _ = v1.iter().step_by(2 / 3);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_const_arrays.fixed b/src/tools/clippy/tests/ui/large_const_arrays.fixed
new file mode 100644
index 00000000000..c5af07c8a17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_const_arrays.fixed
@@ -0,0 +1,37 @@
+// run-rustfix
+
+#![warn(clippy::large_const_arrays)]
+#![allow(dead_code)]
+
+#[derive(Clone, Copy)]
+pub struct S {
+    pub data: [u64; 32],
+}
+
+// Should lint
+pub(crate) static FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
+pub static FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+static FOO: [u32; 1_000_000] = [0u32; 1_000_000];
+
+// Good
+pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000];
+pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000];
+const G_FOO: [u32; 1_000] = [0u32; 1_000];
+
+fn main() {
+    // Should lint
+    pub static BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+    static BAR: [u32; 1_000_000] = [0u32; 1_000_000];
+    pub static BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+    static BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+    pub static BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
+    static BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
+
+    // Good
+    pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000];
+    const G_BAR: [u32; 1_000] = [0u32; 1_000];
+    pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500];
+    const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500];
+    pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200];
+    const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200];
+}
diff --git a/src/tools/clippy/tests/ui/large_const_arrays.rs b/src/tools/clippy/tests/ui/large_const_arrays.rs
new file mode 100644
index 00000000000..a160b9f8ad5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_const_arrays.rs
@@ -0,0 +1,37 @@
+// run-rustfix
+
+#![warn(clippy::large_const_arrays)]
+#![allow(dead_code)]
+
+#[derive(Clone, Copy)]
+pub struct S {
+    pub data: [u64; 32],
+}
+
+// Should lint
+pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
+pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+const FOO: [u32; 1_000_000] = [0u32; 1_000_000];
+
+// Good
+pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000];
+pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000];
+const G_FOO: [u32; 1_000] = [0u32; 1_000];
+
+fn main() {
+    // Should lint
+    pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+    const BAR: [u32; 1_000_000] = [0u32; 1_000_000];
+    pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+    const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+    pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
+    const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
+
+    // Good
+    pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000];
+    const G_BAR: [u32; 1_000] = [0u32; 1_000];
+    pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500];
+    const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500];
+    pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200];
+    const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200];
+}
diff --git a/src/tools/clippy/tests/ui/large_const_arrays.stderr b/src/tools/clippy/tests/ui/large_const_arrays.stderr
new file mode 100644
index 00000000000..3fb0acbca67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_const_arrays.stderr
@@ -0,0 +1,76 @@
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:12:1
+   |
+LL | pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000];
+   | ^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            help: make this a static item: `static`
+   |
+   = note: `-D clippy::large-const-arrays` implied by `-D warnings`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:13:1
+   |
+LL | pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+   | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:14:1
+   |
+LL | const FOO: [u32; 1_000_000] = [0u32; 1_000_000];
+   | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:23:5
+   |
+LL |     pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000];
+   |     ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:24:5
+   |
+LL |     const BAR: [u32; 1_000_000] = [0u32; 1_000_000];
+   |     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:25:5
+   |
+LL |     pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+   |     ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:26:5
+   |
+LL |     const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000];
+   |     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:27:5
+   |
+LL |     pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000];
+   |     ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         help: make this a static item: `static`
+
+error: large array defined as const
+  --> $DIR/large_const_arrays.rs:28:5
+   |
+LL |     const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000];
+   |     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: make this a static item: `static`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.fixed b/src/tools/clippy/tests/ui/large_digit_groups.fixed
new file mode 100644
index 00000000000..859fad2f54d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_digit_groups.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+#![warn(clippy::large_digit_groups)]
+
+fn main() {
+    macro_rules! mac {
+        () => {
+            0b1_10110_i64
+        };
+    }
+
+    let _good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let _bad = (
+        0b11_0110_i64,
+        0xdead_beef_usize,
+        123_456_f32,
+        123_456.12_f32,
+        123_456.123_45_f64,
+        123_456.123_456_f64,
+    );
+    // Ignore literals in macros
+    let _ = mac!();
+}
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.rs b/src/tools/clippy/tests/ui/large_digit_groups.rs
new file mode 100644
index 00000000000..ac116d5dbda
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_digit_groups.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+#![warn(clippy::large_digit_groups)]
+
+fn main() {
+    macro_rules! mac {
+        () => {
+            0b1_10110_i64
+        };
+    }
+
+    let _good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let _bad = (
+        0b1_10110_i64,
+        0xd_e_adbee_f_usize,
+        1_23456_f32,
+        1_23456.12_f32,
+        1_23456.12345_f64,
+        1_23456.12345_6_f64,
+    );
+    // Ignore literals in macros
+    let _ = mac!();
+}
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.stderr b/src/tools/clippy/tests/ui/large_digit_groups.stderr
new file mode 100644
index 00000000000..b6d9672a78e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_digit_groups.stderr
@@ -0,0 +1,42 @@
+error: digit groups should be smaller
+  --> $DIR/large_digit_groups.rs:22:9
+   |
+LL |         0b1_10110_i64,
+   |         ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
+   |
+   = note: `-D clippy::large-digit-groups` implied by `-D warnings`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/large_digit_groups.rs:23:9
+   |
+LL |         0xd_e_adbee_f_usize,
+   |         ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize`
+   |
+   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
+
+error: digit groups should be smaller
+  --> $DIR/large_digit_groups.rs:24:9
+   |
+LL |         1_23456_f32,
+   |         ^^^^^^^^^^^ help: consider: `123_456_f32`
+
+error: digit groups should be smaller
+  --> $DIR/large_digit_groups.rs:25:9
+   |
+LL |         1_23456.12_f32,
+   |         ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32`
+
+error: digit groups should be smaller
+  --> $DIR/large_digit_groups.rs:26:9
+   |
+LL |         1_23456.12345_f64,
+   |         ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f64`
+
+error: digit groups should be smaller
+  --> $DIR/large_digit_groups.rs:27:9
+   |
+LL |         1_23456.12345_6_f64,
+   |         ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs
new file mode 100644
index 00000000000..852ef5fec0e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_enum_variant.rs
@@ -0,0 +1,54 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![warn(clippy::large_enum_variant)]
+
+enum LargeEnum {
+    A(i32),
+    B([i32; 8000]),
+}
+
+enum GenericEnumOk<T> {
+    A(i32),
+    B([T; 8000]),
+}
+
+enum GenericEnum2<T> {
+    A(i32),
+    B([i32; 8000]),
+    C(T, [i32; 8000]),
+}
+
+trait SomeTrait {
+    type Item;
+}
+
+enum LargeEnumGeneric<A: SomeTrait> {
+    Var(A::Item),
+}
+
+enum LargeEnum2 {
+    VariantOk(i32, u32),
+    ContainingLargeEnum(LargeEnum),
+}
+enum LargeEnum3 {
+    ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+    VoidVariant,
+    StructLikeLittle { x: i32, y: i32 },
+}
+
+enum LargeEnum4 {
+    VariantOk(i32, u32),
+    StructLikeLarge { x: [i32; 8000], y: i32 },
+}
+
+enum LargeEnum5 {
+    VariantOk(i32, u32),
+    StructLikeLarge2 { x: [i32; 8000] },
+}
+
+enum LargeEnumOk {
+    LargeA([i32; 8000]),
+    LargeB([i32; 8001]),
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.stderr b/src/tools/clippy/tests/ui/large_enum_variant.stderr
new file mode 100644
index 00000000000..8ce641a81f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_enum_variant.stderr
@@ -0,0 +1,68 @@
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:7:5
+   |
+LL |     B([i32; 8000]),
+   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+   |
+   = note: `-D clippy::large-enum-variant` implied by `-D warnings`
+note: and the second-largest variant is 4 bytes:
+  --> $DIR/large_enum_variant.rs:6:5
+   |
+LL |     A(i32),
+   |     ^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<[i32; 8000]>),
+   |       ^^^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:31:5
+   |
+LL |     ContainingLargeEnum(LargeEnum),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+   |
+note: and the second-largest variant is 8 bytes:
+  --> $DIR/large_enum_variant.rs:30:5
+   |
+LL |     VariantOk(i32, u32),
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     ContainingLargeEnum(Box<LargeEnum>),
+   |                         ^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:41:5
+   |
+LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+   |
+note: and the second-largest variant is 8 bytes:
+  --> $DIR/large_enum_variant.rs:40:5
+   |
+LL |     VariantOk(i32, u32),
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:41:5
+   |
+LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:46:5
+   |
+LL |     StructLikeLarge2 { x: [i32; 8000] },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
+   |
+note: and the second-largest variant is 8 bytes:
+  --> $DIR/large_enum_variant.rs:45:5
+   |
+LL |     VariantOk(i32, u32),
+   |     ^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
+   |                           ^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs
new file mode 100644
index 00000000000..d9161bfcf15
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs
@@ -0,0 +1,30 @@
+#![warn(clippy::large_stack_arrays)]
+#![allow(clippy::large_enum_variant)]
+
+#[derive(Clone, Copy)]
+struct S {
+    pub data: [u64; 32],
+}
+
+#[derive(Clone, Copy)]
+enum E {
+    S(S),
+    T(u32),
+}
+
+fn main() {
+    let bad = (
+        [0u32; 20_000_000],
+        [S { data: [0; 32] }; 5000],
+        [Some(""); 20_000_000],
+        [E::T(0); 5000],
+    );
+
+    let good = (
+        [0u32; 1000],
+        [S { data: [0; 32] }; 1000],
+        [Some(""); 1000],
+        [E::T(0); 1000],
+        [(); 20_000_000],
+    );
+}
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
new file mode 100644
index 00000000000..58c0a77c1c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
@@ -0,0 +1,35 @@
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:17:9
+   |
+LL |         [0u32; 20_000_000],
+   |         ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::large-stack-arrays` implied by `-D warnings`
+   = help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:18:9
+   |
+LL |         [S { data: [0; 32] }; 5000],
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:19:9
+   |
+LL |         [Some(""); 20_000_000],
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()`
+
+error: allocating a local array larger than 512000 bytes
+  --> $DIR/large_stack_arrays.rs:20:9
+   |
+LL |         [E::T(0); 5000],
+   |         ^^^^^^^^^^^^^^^
+   |
+   = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs
new file mode 100644
index 00000000000..3ef29dd6388
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -0,0 +1,145 @@
+#![warn(clippy::len_without_is_empty)]
+#![allow(dead_code, unused)]
+
+pub struct PubOne;
+
+impl PubOne {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+}
+
+impl PubOne {
+    // A second impl for this struct -- the error span shouldn't mention this.
+    pub fn irrelevant(self: &Self) -> bool {
+        false
+    }
+}
+
+// Identical to `PubOne`, but with an `allow` attribute on the impl complaining `len`.
+pub struct PubAllowed;
+
+#[allow(clippy::len_without_is_empty)]
+impl PubAllowed {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+}
+
+// No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the
+// impl containing `len`.
+impl PubAllowed {
+    pub fn irrelevant(self: &Self) -> bool {
+        false
+    }
+}
+
+pub trait PubTraitsToo {
+    fn len(self: &Self) -> isize;
+}
+
+impl PubTraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+pub struct HasIsEmpty;
+
+impl HasIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub struct HasWrongIsEmpty;
+
+impl HasWrongIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    pub fn is_empty(self: &Self, x: u32) -> bool {
+        false
+    }
+}
+
+struct NotPubOne;
+
+impl NotPubOne {
+    pub fn len(self: &Self) -> isize {
+        // No error; `len` is pub but `NotPubOne` is not exported anyway.
+        1
+    }
+}
+
+struct One;
+
+impl One {
+    fn len(self: &Self) -> isize {
+        // No error; `len` is private; see issue #1085.
+        1
+    }
+}
+
+trait TraitsToo {
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
+}
+
+impl TraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+struct HasPrivateIsEmpty;
+
+impl HasPrivateIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+struct Wither;
+
+pub trait WithIsEmpty {
+    fn len(self: &Self) -> isize;
+    fn is_empty(self: &Self) -> bool;
+}
+
+impl WithIsEmpty for Wither {
+    fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub trait Empty {
+    fn is_empty(&self) -> bool;
+}
+
+pub trait InheritingEmpty: Empty {
+    // Must not trigger `LEN_WITHOUT_IS_EMPTY`.
+    fn len(&self) -> isize;
+}
+
+// This used to ICE.
+pub trait Foo: Sized {}
+
+pub trait DependsOnFoo: Foo {
+    fn len(&mut self) -> usize;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
new file mode 100644
index 00000000000..4493b17a4b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
@@ -0,0 +1,54 @@
+error: item `PubOne` has a public `len` method but no corresponding `is_empty` method
+  --> $DIR/len_without_is_empty.rs:6:1
+   |
+LL | / impl PubOne {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::len-without-is-empty` implied by `-D warnings`
+
+error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
+  --> $DIR/len_without_is_empty.rs:37:1
+   |
+LL | / pub trait PubTraitsToo {
+LL | |     fn len(self: &Self) -> isize;
+LL | | }
+   | |_^
+
+error: item `HasIsEmpty` has a public `len` method but a private `is_empty` method
+  --> $DIR/len_without_is_empty.rs:49:1
+   |
+LL | / impl HasIsEmpty {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty` method
+  --> $DIR/len_without_is_empty.rs:61:1
+   |
+LL | / impl HasWrongIsEmpty {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
+  --> $DIR/len_without_is_empty.rs:141:1
+   |
+LL | / pub trait DependsOnFoo: Foo {
+LL | |     fn len(&mut self) -> usize;
+LL | | }
+   | |_^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
new file mode 100644
index 00000000000..624e5ef8fcf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -0,0 +1,143 @@
+// run-rustfix
+
+#![warn(clippy::len_zero)]
+#![allow(dead_code, unused, clippy::len_without_is_empty)]
+
+pub struct One;
+struct Wither;
+
+trait TraitsToo {
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
+}
+
+impl TraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+pub struct HasIsEmpty;
+
+impl HasIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub struct HasWrongIsEmpty;
+
+impl HasWrongIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    pub fn is_empty(self: &Self, x: u32) -> bool {
+        false
+    }
+}
+
+pub trait WithIsEmpty {
+    fn len(self: &Self) -> isize;
+    fn is_empty(self: &Self) -> bool;
+}
+
+impl WithIsEmpty for Wither {
+    fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+fn main() {
+    let x = [1, 2];
+    if x.is_empty() {
+        println!("This should not happen!");
+    }
+
+    if "".is_empty() {}
+
+    let y = One;
+    if y.len() == 0 {
+        // No error; `One` does not have `.is_empty()`.
+        println!("This should not happen either!");
+    }
+
+    let z: &dyn TraitsToo = &y;
+    if z.len() > 0 {
+        // No error; `TraitsToo` has no `.is_empty()` method.
+        println!("Nor should this!");
+    }
+
+    let has_is_empty = HasIsEmpty;
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.len() > 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if has_is_empty.len() <= 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if 1 < has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    if 1 >= has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    assert!(!has_is_empty.is_empty());
+
+    let with_is_empty: &dyn WithIsEmpty = &Wither;
+    if with_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    assert!(!with_is_empty.is_empty());
+
+    let has_wrong_is_empty = HasWrongIsEmpty;
+    if has_wrong_is_empty.len() == 0 {
+        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
+        println!("Or this!");
+    }
+}
+
+fn test_slice(b: &[u8]) {
+    if !b.is_empty() {}
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
new file mode 100644
index 00000000000..7fba971cfd8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -0,0 +1,143 @@
+// run-rustfix
+
+#![warn(clippy::len_zero)]
+#![allow(dead_code, unused, clippy::len_without_is_empty)]
+
+pub struct One;
+struct Wither;
+
+trait TraitsToo {
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
+}
+
+impl TraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+pub struct HasIsEmpty;
+
+impl HasIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub struct HasWrongIsEmpty;
+
+impl HasWrongIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    pub fn is_empty(self: &Self, x: u32) -> bool {
+        false
+    }
+}
+
+pub trait WithIsEmpty {
+    fn len(self: &Self) -> isize;
+    fn is_empty(self: &Self) -> bool;
+}
+
+impl WithIsEmpty for Wither {
+    fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+fn main() {
+    let x = [1, 2];
+    if x.len() == 0 {
+        println!("This should not happen!");
+    }
+
+    if "".len() == 0 {}
+
+    let y = One;
+    if y.len() == 0 {
+        // No error; `One` does not have `.is_empty()`.
+        println!("This should not happen either!");
+    }
+
+    let z: &dyn TraitsToo = &y;
+    if z.len() > 0 {
+        // No error; `TraitsToo` has no `.is_empty()` method.
+        println!("Nor should this!");
+    }
+
+    let has_is_empty = HasIsEmpty;
+    if has_is_empty.len() == 0 {
+        println!("Or this!");
+    }
+    if has_is_empty.len() != 0 {
+        println!("Or this!");
+    }
+    if has_is_empty.len() > 0 {
+        println!("Or this!");
+    }
+    if has_is_empty.len() < 1 {
+        println!("Or this!");
+    }
+    if has_is_empty.len() >= 1 {
+        println!("Or this!");
+    }
+    if has_is_empty.len() > 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if has_is_empty.len() <= 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if 0 == has_is_empty.len() {
+        println!("Or this!");
+    }
+    if 0 != has_is_empty.len() {
+        println!("Or this!");
+    }
+    if 0 < has_is_empty.len() {
+        println!("Or this!");
+    }
+    if 1 <= has_is_empty.len() {
+        println!("Or this!");
+    }
+    if 1 > has_is_empty.len() {
+        println!("Or this!");
+    }
+    if 1 < has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    if 1 >= has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    assert!(!has_is_empty.is_empty());
+
+    let with_is_empty: &dyn WithIsEmpty = &Wither;
+    if with_is_empty.len() == 0 {
+        println!("Or this!");
+    }
+    assert!(!with_is_empty.is_empty());
+
+    let has_wrong_is_empty = HasWrongIsEmpty;
+    if has_wrong_is_empty.len() == 0 {
+        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
+        println!("Or this!");
+    }
+}
+
+fn test_slice(b: &[u8]) {
+    if b.len() != 0 {}
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
new file mode 100644
index 00000000000..6c71f1beeac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -0,0 +1,88 @@
+error: length comparison to zero
+  --> $DIR/len_zero.rs:61:8
+   |
+LL |     if x.len() == 0 {
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
+   |
+   = note: `-D clippy::len-zero` implied by `-D warnings`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:65:8
+   |
+LL |     if "".len() == 0 {}
+   |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:80:8
+   |
+LL |     if has_is_empty.len() == 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:83:8
+   |
+LL |     if has_is_empty.len() != 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:86:8
+   |
+LL |     if has_is_empty.len() > 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to one
+  --> $DIR/len_zero.rs:89:8
+   |
+LL |     if has_is_empty.len() < 1 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to one
+  --> $DIR/len_zero.rs:92:8
+   |
+LL |     if has_is_empty.len() >= 1 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:103:8
+   |
+LL |     if 0 == has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:106:8
+   |
+LL |     if 0 != has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:109:8
+   |
+LL |     if 0 < has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to one
+  --> $DIR/len_zero.rs:112:8
+   |
+LL |     if 1 <= has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
+
+error: length comparison to one
+  --> $DIR/len_zero.rs:115:8
+   |
+LL |     if 1 > has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:129:8
+   |
+LL |     if with_is_empty.len() == 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
+
+error: length comparison to zero
+  --> $DIR/len_zero.rs:142:8
+   |
+LL |     if b.len() != 0 {}
+   |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
new file mode 100644
index 00000000000..802beeb4be6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -0,0 +1,119 @@
+#![allow(
+    unused_variables,
+    unused_assignments,
+    clippy::similar_names,
+    clippy::blacklisted_name
+)]
+#![warn(clippy::useless_let_if_seq)]
+
+fn f() -> bool {
+    true
+}
+fn g(x: i32) -> i32 {
+    x + 1
+}
+
+fn issue985() -> i32 {
+    let mut x = 42;
+    if f() {
+        x = g(x);
+    }
+
+    x
+}
+
+fn issue985_alt() -> i32 {
+    let mut x = 42;
+    if f() {
+        f();
+    } else {
+        x = g(x);
+    }
+
+    x
+}
+
+fn issue975() -> String {
+    let mut udn = "dummy".to_string();
+    if udn.starts_with("uuid:") {
+        udn = String::from(&udn[5..]);
+    }
+    udn
+}
+
+fn early_return() -> u8 {
+    // FIXME: we could extend the lint to include such cases:
+    let foo;
+
+    if f() {
+        return 42;
+    } else {
+        foo = 0;
+    }
+
+    foo
+}
+
+fn main() {
+    early_return();
+    issue975();
+    issue985();
+    issue985_alt();
+
+    let mut foo = 0;
+    if f() {
+        foo = 42;
+    }
+
+    let mut bar = 0;
+    if f() {
+        f();
+        bar = 42;
+    } else {
+        f();
+    }
+
+    let quz;
+    if f() {
+        quz = 42;
+    } else {
+        quz = 0;
+    }
+
+    // `toto` is used several times
+    let mut toto;
+    if f() {
+        toto = 42;
+    } else {
+        for i in &[1, 2] {
+            toto = *i;
+        }
+
+        toto = 2;
+    }
+
+    // found in libcore, the inner if is not a statement but the block's expr
+    let mut ch = b'x';
+    if f() {
+        ch = b'*';
+        if f() {
+            ch = b'?';
+        }
+    }
+
+    // baz needs to be mut
+    let mut baz = 0;
+    if f() {
+        baz = 42;
+    }
+
+    baz = 1337;
+
+    // issue 3043 - types with interior mutability should not trigger this lint
+    use std::cell::Cell;
+    let mut val = Cell::new(1);
+    if true {
+        val = Cell::new(2);
+    }
+    println!("{}", val.get());
+}
diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr
new file mode 100644
index 00000000000..c53a63a541b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_if_seq.stderr
@@ -0,0 +1,50 @@
+error: `if _ { .. } else { .. }` is an expression
+  --> $DIR/let_if_seq.rs:63:5
+   |
+LL | /     let mut foo = 0;
+LL | |     if f() {
+LL | |         foo = 42;
+LL | |     }
+   | |_____^ help: it is more idiomatic to write: `let <mut> foo = if f() { 42 } else { 0 };`
+   |
+   = note: `-D clippy::useless-let-if-seq` implied by `-D warnings`
+   = note: you might not need `mut` at all
+
+error: `if _ { .. } else { .. }` is an expression
+  --> $DIR/let_if_seq.rs:68:5
+   |
+LL | /     let mut bar = 0;
+LL | |     if f() {
+LL | |         f();
+LL | |         bar = 42;
+LL | |     } else {
+LL | |         f();
+LL | |     }
+   | |_____^ help: it is more idiomatic to write: `let <mut> bar = if f() { ..; 42 } else { ..; 0 };`
+   |
+   = note: you might not need `mut` at all
+
+error: `if _ { .. } else { .. }` is an expression
+  --> $DIR/let_if_seq.rs:76:5
+   |
+LL | /     let quz;
+LL | |     if f() {
+LL | |         quz = 42;
+LL | |     } else {
+LL | |         quz = 0;
+LL | |     }
+   | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
+
+error: `if _ { .. } else { .. }` is an expression
+  --> $DIR/let_if_seq.rs:105:5
+   |
+LL | /     let mut baz = 0;
+LL | |     if f() {
+LL | |         baz = 42;
+LL | |     }
+   | |_____^ help: it is more idiomatic to write: `let <mut> baz = if f() { 42 } else { 0 };`
+   |
+   = note: you might not need `mut` at all
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_return.rs b/src/tools/clippy/tests/ui/let_return.rs
new file mode 100644
index 00000000000..23645d48fe7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_return.rs
@@ -0,0 +1,70 @@
+#![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/let_return.stderr b/src/tools/clippy/tests/ui/let_return.stderr
new file mode 100644
index 00000000000..128a22c86e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_return.stderr
@@ -0,0 +1,31 @@
+error: returning the result of a `let` binding from a block
+  --> $DIR/let_return.rs:7:5
+   |
+LL |     let x = 5;
+   |     ---------- unnecessary `let` binding
+LL |     x
+   |     ^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+help: return the expression directly
+   |
+LL |     
+LL |     5
+   |
+
+error: returning the result of a `let` binding from a block
+  --> $DIR/let_return.rs:13:9
+   |
+LL |         let x = 5;
+   |         ---------- unnecessary `let` binding
+LL |         x
+   |         ^
+   |
+help: return the expression directly
+   |
+LL |         
+LL |         5
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.rs b/src/tools/clippy/tests/ui/let_underscore_lock.rs
new file mode 100644
index 00000000000..88fb216a743
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::let_underscore_lock)]
+
+fn main() {
+    let m = std::sync::Mutex::new(());
+    let rw = std::sync::RwLock::new(());
+
+    let _ = m.lock();
+    let _ = rw.read();
+    let _ = rw.write();
+    let _ = m.try_lock();
+    let _ = rw.try_read();
+    let _ = rw.try_write();
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
new file mode 100644
index 00000000000..5d5f6059ef1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
@@ -0,0 +1,51 @@
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:7:5
+   |
+LL |     let _ = m.lock();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::let-underscore-lock` implied by `-D warnings`
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:8:5
+   |
+LL |     let _ = rw.read();
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:9:5
+   |
+LL |     let _ = rw.write();
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:10:5
+   |
+LL |     let _ = m.try_lock();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:11:5
+   |
+LL |     let _ = rw.try_read();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:12:5
+   |
+LL |     let _ = rw.try_write();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.rs b/src/tools/clippy/tests/ui/let_underscore_must_use.rs
new file mode 100644
index 00000000000..27dda606067
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_must_use.rs
@@ -0,0 +1,94 @@
+#![warn(clippy::let_underscore_must_use)]
+
+// Debug implementations can fire this lint,
+// so we shouldn't lint external macros
+#[derive(Debug)]
+struct Foo {
+    field: i32,
+}
+
+#[must_use]
+fn f() -> u32 {
+    0
+}
+
+fn g() -> Result<u32, u32> {
+    Ok(0)
+}
+
+#[must_use]
+fn l<T>(x: T) -> T {
+    x
+}
+
+fn h() -> u32 {
+    0
+}
+
+struct S {}
+
+impl S {
+    #[must_use]
+    pub fn f(&self) -> u32 {
+        0
+    }
+
+    pub fn g(&self) -> Result<u32, u32> {
+        Ok(0)
+    }
+
+    fn k(&self) -> u32 {
+        0
+    }
+
+    #[must_use]
+    fn h() -> u32 {
+        0
+    }
+
+    fn p() -> Result<u32, u32> {
+        Ok(0)
+    }
+}
+
+trait Trait {
+    #[must_use]
+    fn a() -> u32;
+}
+
+impl Trait for S {
+    fn a() -> u32 {
+        0
+    }
+}
+
+fn main() {
+    let _ = f();
+    let _ = g();
+    let _ = h();
+    let _ = l(0_u32);
+
+    let s = S {};
+
+    let _ = s.f();
+    let _ = s.g();
+    let _ = s.k();
+
+    let _ = S::h();
+    let _ = S::p();
+
+    let _ = S::a();
+
+    let _ = if true { Ok(()) } else { Err(()) };
+
+    let a = Result::<(), ()>::Ok(());
+
+    let _ = a.is_ok();
+
+    let _ = a.map(|_| ());
+
+    let _ = a;
+
+    #[allow(clippy::let_underscore_must_use)]
+    let _ = a;
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr
new file mode 100644
index 00000000000..447f2419e3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr
@@ -0,0 +1,99 @@
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:66:5
+   |
+LL |     let _ = f();
+   |     ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::let-underscore-must-use` implied by `-D warnings`
+   = help: consider explicitly using function result
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:67:5
+   |
+LL |     let _ = g();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:69:5
+   |
+LL |     let _ = l(0_u32);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using function result
+
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:73:5
+   |
+LL |     let _ = s.f();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using function result
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:74:5
+   |
+LL |     let _ = s.g();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:77:5
+   |
+LL |     let _ = S::h();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using function result
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:78:5
+   |
+LL |     let _ = S::p();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:80:5
+   |
+LL |     let _ = S::a();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using function result
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:82:5
+   |
+LL |     let _ = if true { Ok(()) } else { Err(()) };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: non-binding let on a result of a `#[must_use]` function
+  --> $DIR/let_underscore_must_use.rs:86:5
+   |
+LL |     let _ = a.is_ok();
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using function result
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:88:5
+   |
+LL |     let _ = a.map(|_| ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: non-binding let on an expression with `#[must_use]` type
+  --> $DIR/let_underscore_must_use.rs:90:5
+   |
+LL |     let _ = a;
+   |     ^^^^^^^^^^
+   |
+   = help: consider explicitly using expression value
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
new file mode 100644
index 00000000000..f398edc23cb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::let_unit_value)]
+#![allow(clippy::no_effect)]
+#![allow(unused_variables)]
+
+macro_rules! let_and_return {
+    ($n:expr) => {{
+        let ret = $n;
+    }};
+}
+
+fn main() {
+    println!("x");
+    let _y = 1; // this is fine
+    let _z = ((), 1); // this as well
+    if true {
+        ();
+    }
+
+    consume_units_with_for_loop(); // should be fine as well
+
+    multiline_sugg();
+
+    let_and_return!(()) // should be fine
+}
+
+// Related to issue #1964
+fn consume_units_with_for_loop() {
+    // `for_let_unit` lint should not be triggered by consuming them using for loop.
+    let v = vec![(), (), ()];
+    let mut count = 0;
+    for _ in v {
+        count += 1;
+    }
+    assert_eq!(count, 3);
+
+    // Same for consuming from some other Iterator<Item = ()>.
+    let (tx, rx) = ::std::sync::mpsc::channel();
+    tx.send(()).unwrap();
+    drop(tx);
+
+    count = 0;
+    for _ in rx.iter() {
+        count += 1;
+    }
+    assert_eq!(count, 1);
+}
+
+fn multiline_sugg() {
+    let v: Vec<u8> = vec![2];
+
+    v
+        .into_iter()
+        .map(|i| i * 2)
+        .filter(|i| i % 2 == 0)
+        .map(|_| ())
+        .next()
+        .unwrap();
+}
+
+#[derive(Copy, Clone)]
+pub struct ContainsUnit(()); // should be fine
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
new file mode 100644
index 00000000000..af5b1fb2ac7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::let_unit_value)]
+#![allow(clippy::no_effect)]
+#![allow(unused_variables)]
+
+macro_rules! let_and_return {
+    ($n:expr) => {{
+        let ret = $n;
+    }};
+}
+
+fn main() {
+    let _x = println!("x");
+    let _y = 1; // this is fine
+    let _z = ((), 1); // this as well
+    if true {
+        let _a = ();
+    }
+
+    consume_units_with_for_loop(); // should be fine as well
+
+    multiline_sugg();
+
+    let_and_return!(()) // should be fine
+}
+
+// Related to issue #1964
+fn consume_units_with_for_loop() {
+    // `for_let_unit` lint should not be triggered by consuming them using for loop.
+    let v = vec![(), (), ()];
+    let mut count = 0;
+    for _ in v {
+        count += 1;
+    }
+    assert_eq!(count, 3);
+
+    // Same for consuming from some other Iterator<Item = ()>.
+    let (tx, rx) = ::std::sync::mpsc::channel();
+    tx.send(()).unwrap();
+    drop(tx);
+
+    count = 0;
+    for _ in rx.iter() {
+        count += 1;
+    }
+    assert_eq!(count, 1);
+}
+
+fn multiline_sugg() {
+    let v: Vec<u8> = vec![2];
+
+    let _ = v
+        .into_iter()
+        .map(|i| i * 2)
+        .filter(|i| i % 2 == 0)
+        .map(|_| ())
+        .next()
+        .unwrap();
+}
+
+#[derive(Copy, Clone)]
+pub struct ContainsUnit(()); // should be fine
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
new file mode 100644
index 00000000000..eb8482087bc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -0,0 +1,38 @@
+error: this let-binding has unit value
+  --> $DIR/let_unit.rs:14:5
+   |
+LL |     let _x = println!("x");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");`
+   |
+   = note: `-D clippy::let-unit-value` implied by `-D warnings`
+
+error: this let-binding has unit value
+  --> $DIR/let_unit.rs:18:9
+   |
+LL |         let _a = ();
+   |         ^^^^^^^^^^^^ help: omit the `let` binding: `();`
+
+error: this let-binding has unit value
+  --> $DIR/let_unit.rs:53:5
+   |
+LL | /     let _ = v
+LL | |         .into_iter()
+LL | |         .map(|i| i * 2)
+LL | |         .filter(|i| i % 2 == 0)
+LL | |         .map(|_| ())
+LL | |         .next()
+LL | |         .unwrap();
+   | |__________________^
+   |
+help: omit the `let` binding
+   |
+LL |     v
+LL |         .into_iter()
+LL |         .map(|i| i * 2)
+LL |         .filter(|i| i % 2 == 0)
+LL |         .map(|_| ())
+LL |         .next()
+ ...
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/lint_without_lint_pass.rs b/src/tools/clippy/tests/ui/lint_without_lint_pass.rs
new file mode 100644
index 00000000000..beaef79a340
--- /dev/null
+++ b/src/tools/clippy/tests/ui/lint_without_lint_pass.rs
@@ -0,0 +1,44 @@
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+extern crate rustc_lint;
+use rustc_lint::LintPass;
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT_REGISTERED,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub clippy::TEST_LINT_REGISTERED_ONLY_IMPL,
+    Warn,
+    "",
+    report_in_external_macro: true
+}
+
+pub struct Pass;
+impl LintPass for Pass {
+    fn name(&self) -> &'static str {
+        "TEST_LINT"
+    }
+}
+
+declare_lint_pass!(Pass2 => [TEST_LINT_REGISTERED]);
+
+pub struct Pass3;
+impl_lint_pass!(Pass3 => [TEST_LINT_REGISTERED_ONLY_IMPL]);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/lint_without_lint_pass.stderr b/src/tools/clippy/tests/ui/lint_without_lint_pass.stderr
new file mode 100644
index 00000000000..1257dae96d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/lint_without_lint_pass.stderr
@@ -0,0 +1,21 @@
+error: the lint `TEST_LINT` is not added to any `LintPass`
+  --> $DIR/lint_without_lint_pass.rs:11:1
+   |
+LL | / declare_tool_lint! {
+LL | |     pub clippy::TEST_LINT,
+LL | |     Warn,
+LL | |     "",
+LL | |     report_in_external_macro: true
+LL | | }
+   | |_^
+   |
+note: the lint level is defined here
+  --> $DIR/lint_without_lint_pass.rs:1:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::lint_without_lint_pass)]` implied by `#[deny(clippy::internal)]`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/literals.rs b/src/tools/clippy/tests/ui/literals.rs
new file mode 100644
index 00000000000..c299b16c8ce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/literals.rs
@@ -0,0 +1,36 @@
+// does not test any rustfixable lints
+
+#![warn(clippy::mixed_case_hex_literals)]
+#![warn(clippy::zero_prefixed_literal)]
+#![allow(clippy::unseparated_literal_suffix)]
+#![allow(dead_code)]
+
+fn main() {
+    let ok1 = 0xABCD;
+    let ok3 = 0xab_cd;
+    let ok4 = 0xab_cd_i32;
+    let ok5 = 0xAB_CD_u32;
+    let ok5 = 0xAB_CD_isize;
+    let fail1 = 0xabCD;
+    let fail2 = 0xabCD_u32;
+    let fail2 = 0xabCD_isize;
+    let fail_multi_zero = 000_123usize;
+
+    let ok9 = 0;
+    let ok10 = 0_i64;
+    let fail8 = 0123;
+
+    let ok11 = 0o123;
+    let ok12 = 0b10_1010;
+
+    let ok13 = 0xab_abcd;
+    let ok14 = 0xBAFE_BAFE;
+    let ok15 = 0xab_cabc_abca_bcab_cabc;
+    let ok16 = 0xFE_BAFE_ABAB_ABCD;
+    let ok17 = 0x123_4567_8901_usize;
+    let ok18 = 0xF;
+
+    let fail19 = 12_3456_21;
+    let fail22 = 3__4___23;
+    let fail23 = 3__16___23;
+}
diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr
new file mode 100644
index 00000000000..0b3af2d8bc3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/literals.stderr
@@ -0,0 +1,73 @@
+error: inconsistent casing in hexadecimal literal
+  --> $DIR/literals.rs:14:17
+   |
+LL |     let fail1 = 0xabCD;
+   |                 ^^^^^^
+   |
+   = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
+
+error: inconsistent casing in hexadecimal literal
+  --> $DIR/literals.rs:15:17
+   |
+LL |     let fail2 = 0xabCD_u32;
+   |                 ^^^^^^^^^^
+
+error: inconsistent casing in hexadecimal literal
+  --> $DIR/literals.rs:16:17
+   |
+LL |     let fail2 = 0xabCD_isize;
+   |                 ^^^^^^^^^^^^
+
+error: this is a decimal constant
+  --> $DIR/literals.rs:17:27
+   |
+LL |     let fail_multi_zero = 000_123usize;
+   |                           ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+   |
+LL |     let fail_multi_zero = 123usize;
+   |                           ^^^^^^^^
+help: if you mean to use an octal constant, use `0o`
+   |
+LL |     let fail_multi_zero = 0o123usize;
+   |                           ^^^^^^^^^^
+
+error: this is a decimal constant
+  --> $DIR/literals.rs:21:17
+   |
+LL |     let fail8 = 0123;
+   |                 ^^^^
+   |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+   |
+LL |     let fail8 = 123;
+   |                 ^^^
+help: if you mean to use an octal constant, use `0o`
+   |
+LL |     let fail8 = 0o123;
+   |                 ^^^^^
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/literals.rs:33:18
+   |
+LL |     let fail19 = 12_3456_21;
+   |                  ^^^^^^^^^^ help: consider: `12_345_621`
+   |
+   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/literals.rs:34:18
+   |
+LL |     let fail22 = 3__4___23;
+   |                  ^^^^^^^^^ help: consider: `3_423`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/literals.rs:35:18
+   |
+LL |     let fail23 = 3__16___23;
+   |                  ^^^^^^^^^^ help: consider: `31_623`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/logic_bug.rs
new file mode 100644
index 00000000000..b4163d776e7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/logic_bug.rs
@@ -0,0 +1,26 @@
+#![allow(unused, clippy::many_single_char_names)]
+#![warn(clippy::logic_bug)]
+
+fn main() {
+    let a: bool = unimplemented!();
+    let b: bool = unimplemented!();
+    let c: bool = unimplemented!();
+    let d: bool = unimplemented!();
+    let e: bool = unimplemented!();
+    let _ = a && b || a;
+    let _ = !(a && b);
+    let _ = false && a;
+    // don't lint on cfgs
+    let _ = cfg!(you_shall_not_not_pass) && a;
+    let _ = a || !b || !c || !d || !e;
+    let _ = !(a && b || c);
+}
+
+fn equality_stuff() {
+    let a: i32 = unimplemented!();
+    let b: i32 = unimplemented!();
+    let _ = a == b && a != b;
+    let _ = a < b && a >= b;
+    let _ = a > b && a <= b;
+    let _ = a > b && a == b;
+}
diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/logic_bug.stderr
new file mode 100644
index 00000000000..8f55e1c8ad8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/logic_bug.stderr
@@ -0,0 +1,63 @@
+error: this boolean expression contains a logic bug
+  --> $DIR/logic_bug.rs:10:13
+   |
+LL |     let _ = a && b || a;
+   |             ^^^^^^^^^^^ help: it would look like the following: `a`
+   |
+   = note: `-D clippy::logic-bug` implied by `-D warnings`
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/logic_bug.rs:10:18
+   |
+LL |     let _ = a && b || a;
+   |                  ^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/logic_bug.rs:12:13
+   |
+LL |     let _ = false && a;
+   |             ^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/logic_bug.rs:12:22
+   |
+LL |     let _ = false && a;
+   |                      ^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/logic_bug.rs:22:13
+   |
+LL |     let _ = a == b && a != b;
+   |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/logic_bug.rs:22:13
+   |
+LL |     let _ = a == b && a != b;
+   |             ^^^^^^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/logic_bug.rs:23:13
+   |
+LL |     let _ = a < b && a >= b;
+   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/logic_bug.rs:23:13
+   |
+LL |     let _ = a < b && a >= b;
+   |             ^^^^^
+
+error: this boolean expression contains a logic bug
+  --> $DIR/logic_bug.rs:24:13
+   |
+LL |     let _ = a > b && a <= b;
+   |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+   |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+  --> $DIR/logic_bug.rs:24:13
+   |
+LL |     let _ = a > b && a <= b;
+   |             ^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.fixed b/src/tools/clippy/tests/ui/lossy_float_literal.fixed
new file mode 100644
index 00000000000..24e372354fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.fixed
@@ -0,0 +1,35 @@
+// run-rustfix
+#![warn(clippy::lossy_float_literal)]
+
+fn main() {
+    // Lossy whole-number float literals
+    let _: f32 = 16_777_216.0;
+    let _: f32 = 16_777_220.0;
+    let _: f32 = 16_777_220.0;
+    let _: f32 = 16_777_220.0;
+    let _ = 16_777_220_f32;
+    let _: f32 = -16_777_220.0;
+    let _: f64 = 9_007_199_254_740_992.0;
+    let _: f64 = 9_007_199_254_740_992.0;
+    let _: f64 = 9_007_199_254_740_992.0;
+    let _ = 9_007_199_254_740_992_f64;
+    let _: f64 = -9_007_199_254_740_992.0;
+
+    // Lossless whole number float literals
+    let _: f32 = 16_777_216.0;
+    let _: f32 = 16_777_218.0;
+    let _: f32 = 16_777_220.0;
+    let _: f32 = -16_777_216.0;
+    let _: f32 = -16_777_220.0;
+    let _: f64 = 16_777_217.0;
+    let _: f64 = -16_777_217.0;
+    let _: f64 = 9_007_199_254_740_992.0;
+    let _: f64 = -9_007_199_254_740_992.0;
+
+    // Ignored whole number float literals
+    let _: f32 = 1e25;
+    let _: f32 = 1E25;
+    let _: f64 = 1e99;
+    let _: f64 = 1E99;
+    let _: f32 = 0.1;
+}
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.rs b/src/tools/clippy/tests/ui/lossy_float_literal.rs
new file mode 100644
index 00000000000..3dcf98fa0bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.rs
@@ -0,0 +1,35 @@
+// run-rustfix
+#![warn(clippy::lossy_float_literal)]
+
+fn main() {
+    // Lossy whole-number float literals
+    let _: f32 = 16_777_217.0;
+    let _: f32 = 16_777_219.0;
+    let _: f32 = 16_777_219.;
+    let _: f32 = 16_777_219.000;
+    let _ = 16_777_219f32;
+    let _: f32 = -16_777_219.0;
+    let _: f64 = 9_007_199_254_740_993.0;
+    let _: f64 = 9_007_199_254_740_993.;
+    let _: f64 = 9_007_199_254_740_993.00;
+    let _ = 9_007_199_254_740_993f64;
+    let _: f64 = -9_007_199_254_740_993.0;
+
+    // Lossless whole number float literals
+    let _: f32 = 16_777_216.0;
+    let _: f32 = 16_777_218.0;
+    let _: f32 = 16_777_220.0;
+    let _: f32 = -16_777_216.0;
+    let _: f32 = -16_777_220.0;
+    let _: f64 = 16_777_217.0;
+    let _: f64 = -16_777_217.0;
+    let _: f64 = 9_007_199_254_740_992.0;
+    let _: f64 = -9_007_199_254_740_992.0;
+
+    // Ignored whole number float literals
+    let _: f32 = 1e25;
+    let _: f32 = 1E25;
+    let _: f64 = 1e99;
+    let _: f64 = 1E99;
+    let _: f32 = 0.1;
+}
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
new file mode 100644
index 00000000000..d2193c0c819
--- /dev/null
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
@@ -0,0 +1,70 @@
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:6:18
+   |
+LL |     let _: f32 = 16_777_217.0;
+   |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0`
+   |
+   = note: `-D clippy::lossy-float-literal` implied by `-D warnings`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:7:18
+   |
+LL |     let _: f32 = 16_777_219.0;
+   |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:8:18
+   |
+LL |     let _: f32 = 16_777_219.;
+   |                  ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:9:18
+   |
+LL |     let _: f32 = 16_777_219.000;
+   |                  ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:10:13
+   |
+LL |     let _ = 16_777_219f32;
+   |             ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:11:19
+   |
+LL |     let _: f32 = -16_777_219.0;
+   |                   ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:12:18
+   |
+LL |     let _: f64 = 9_007_199_254_740_993.0;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:13:18
+   |
+LL |     let _: f64 = 9_007_199_254_740_993.;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:14:18
+   |
+LL |     let _: f64 = 9_007_199_254_740_993.00;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:15:13
+   |
+LL |     let _ = 9_007_199_254_740_993f64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64`
+
+error: literal cannot be represented as the underlying type without loss of precision
+  --> $DIR/lossy_float_literal.rs:16:19
+   |
+LL |     let _: f64 = -9_007_199_254_740_993.0;
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs
new file mode 100644
index 00000000000..60c64ee8146
--- /dev/null
+++ b/src/tools/clippy/tests/ui/macro_use_imports.rs
@@ -0,0 +1,11 @@
+// edition:2018
+#![warn(clippy::macro_use_imports)]
+
+use std::collections::HashMap;
+#[macro_use]
+use std::prelude;
+
+fn main() {
+    let _ = HashMap::<u8, u8>::new();
+    println!();
+}
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr
new file mode 100644
index 00000000000..b5e3dbec572
--- /dev/null
+++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr
@@ -0,0 +1,10 @@
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:5:1
+   |
+LL | #[macro_use]
+   | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>`
+   |
+   = note: `-D clippy::macro-use-imports` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/manual_memcpy.rs b/src/tools/clippy/tests/ui/manual_memcpy.rs
new file mode 100644
index 00000000000..aa347288875
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_memcpy.rs
@@ -0,0 +1,110 @@
+#![warn(clippy::needless_range_loop, clippy::manual_memcpy)]
+
+const LOOP_OFFSET: usize = 5000;
+
+pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
+    // plain manual memcpy
+    for i in 0..src.len() {
+        dst[i] = src[i];
+    }
+
+    // dst offset memcpy
+    for i in 0..src.len() {
+        dst[i + 10] = src[i];
+    }
+
+    // src offset memcpy
+    for i in 0..src.len() {
+        dst[i] = src[i + 10];
+    }
+
+    // src offset memcpy
+    for i in 11..src.len() {
+        dst[i] = src[i - 10];
+    }
+
+    // overwrite entire dst
+    for i in 0..dst.len() {
+        dst[i] = src[i];
+    }
+
+    // manual copy with branch - can't easily convert to memcpy!
+    for i in 0..src.len() {
+        dst[i] = src[i];
+        if dst[i] > 5 {
+            break;
+        }
+    }
+
+    // multiple copies - suggest two memcpy statements
+    for i in 10..256 {
+        dst[i] = src[i - 5];
+        dst2[i + 500] = src[i]
+    }
+
+    // this is a reversal - the copy lint shouldn't be triggered
+    for i in 10..LOOP_OFFSET {
+        dst[i + LOOP_OFFSET] = src[LOOP_OFFSET - i];
+    }
+
+    let some_var = 5;
+    // Offset in variable
+    for i in 10..LOOP_OFFSET {
+        dst[i + LOOP_OFFSET] = src[i - some_var];
+    }
+
+    // Non continuous copy - don't trigger lint
+    for i in 0..10 {
+        dst[i + i] = src[i];
+    }
+
+    let src_vec = vec![1, 2, 3, 4, 5];
+    let mut dst_vec = vec![0, 0, 0, 0, 0];
+
+    // make sure vectors are supported
+    for i in 0..src_vec.len() {
+        dst_vec[i] = src_vec[i];
+    }
+
+    // lint should not trigger when either
+    // source or destination type is not
+    // slice-like, like DummyStruct
+    struct DummyStruct(i32);
+
+    impl ::std::ops::Index<usize> for DummyStruct {
+        type Output = i32;
+
+        fn index(&self, _: usize) -> &i32 {
+            &self.0
+        }
+    }
+
+    let src = DummyStruct(5);
+    let mut dst_vec = vec![0; 10];
+
+    for i in 0..10 {
+        dst_vec[i] = src[i];
+    }
+
+    // Simplify suggestion (issue #3004)
+    let src = [0, 1, 2, 3, 4];
+    let mut dst = [0, 0, 0, 0, 0, 0];
+    let from = 1;
+
+    for i in from..from + src.len() {
+        dst[i] = src[i - from];
+    }
+
+    for i in from..from + 3 {
+        dst[i] = src[i - from];
+    }
+}
+
+#[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
+pub fn manual_clone(src: &[String], dst: &mut [String]) {
+    for i in 0..src.len() {
+        dst[i] = src[i].clone();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_memcpy.stderr b/src/tools/clippy/tests/ui/manual_memcpy.stderr
new file mode 100644
index 00000000000..3dbb2155d4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_memcpy.stderr
@@ -0,0 +1,76 @@
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:7:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
+   |
+   = note: `-D clippy::manual-memcpy` implied by `-D warnings`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:12:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:17:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:22:14
+   |
+LL |     for i in 11..src.len() {
+   |              ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:27:14
+   |
+LL |     for i in 0..dst.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:40:14
+   |
+LL |     for i in 10..256 {
+   |              ^^^^^^^
+   |
+help: try replacing the loop by
+   |
+LL |     for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)])
+LL |     dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) {
+   |
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:52:14
+   |
+LL |     for i in 10..LOOP_OFFSET {
+   |              ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:65:14
+   |
+LL |     for i in 0..src_vec.len() {
+   |              ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:94:14
+   |
+LL |     for i in from..from + src.len() {
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:98:14
+   |
+LL |     for i in from..from + 3 {
+   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:105:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
new file mode 100644
index 00000000000..c4f53c446c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#![allow(unused_imports)]
+
+use std::{i128, i32, u128, u32};
+
+fn main() {
+    let _ = 1u32.saturating_add(1);
+    let _ = 1u32.saturating_add(1);
+    let _ = 1u8.saturating_add(1);
+    let _ = 1u128.saturating_add(1);
+    let _ = 1u32.checked_add(1).unwrap_or(1234); // ok
+    let _ = 1u8.checked_add(1).unwrap_or(0); // ok
+    let _ = 1u32.saturating_mul(1);
+
+    let _ = 1u32.saturating_sub(1);
+    let _ = 1u32.saturating_sub(1);
+    let _ = 1u8.saturating_sub(1);
+    let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok
+    let _ = 1u8.checked_sub(1).unwrap_or(255); // ok
+
+    let _ = 1i32.saturating_add(1);
+    let _ = 1i32.saturating_add(1);
+    let _ = 1i8.saturating_add(1);
+    let _ = 1i128.saturating_add(1);
+    let _ = 1i32.saturating_add(-1);
+    let _ = 1i32.saturating_add(-1);
+    let _ = 1i8.saturating_add(-1);
+    let _ = 1i128.saturating_add(-1);
+    let _ = 1i32.checked_add(1).unwrap_or(1234); // ok
+    let _ = 1i8.checked_add(1).unwrap_or(-128); // ok
+    let _ = 1i8.checked_add(-1).unwrap_or(127); // ok
+
+    let _ = 1i32.saturating_sub(1);
+    let _ = 1i32.saturating_sub(1);
+    let _ = 1i8.saturating_sub(1);
+    let _ = 1i128.saturating_sub(1);
+    let _ = 1i32.saturating_sub(-1);
+    let _ = 1i32.saturating_sub(-1);
+    let _ = 1i8.saturating_sub(-1);
+    let _ = 1i128.saturating_sub(-1);
+    let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok
+    let _ = 1i8.checked_sub(1).unwrap_or(127); // ok
+    let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok
+}
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
new file mode 100644
index 00000000000..cd83cf6e65e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
@@ -0,0 +1,55 @@
+// run-rustfix
+
+#![allow(unused_imports)]
+
+use std::{i128, i32, u128, u32};
+
+fn main() {
+    let _ = 1u32.checked_add(1).unwrap_or(u32::max_value());
+    let _ = 1u32.checked_add(1).unwrap_or(u32::MAX);
+    let _ = 1u8.checked_add(1).unwrap_or(255);
+    let _ = 1u128
+        .checked_add(1)
+        .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455);
+    let _ = 1u32.checked_add(1).unwrap_or(1234); // ok
+    let _ = 1u8.checked_add(1).unwrap_or(0); // ok
+    let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX);
+
+    let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value());
+    let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN);
+    let _ = 1u8.checked_sub(1).unwrap_or(0);
+    let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok
+    let _ = 1u8.checked_sub(1).unwrap_or(255); // ok
+
+    let _ = 1i32.checked_add(1).unwrap_or(i32::max_value());
+    let _ = 1i32.checked_add(1).unwrap_or(i32::MAX);
+    let _ = 1i8.checked_add(1).unwrap_or(127);
+    let _ = 1i128
+        .checked_add(1)
+        .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727);
+    let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value());
+    let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN);
+    let _ = 1i8.checked_add(-1).unwrap_or(-128);
+    let _ = 1i128
+        .checked_add(-1)
+        .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
+    let _ = 1i32.checked_add(1).unwrap_or(1234); // ok
+    let _ = 1i8.checked_add(1).unwrap_or(-128); // ok
+    let _ = 1i8.checked_add(-1).unwrap_or(127); // ok
+
+    let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value());
+    let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN);
+    let _ = 1i8.checked_sub(1).unwrap_or(-128);
+    let _ = 1i128
+        .checked_sub(1)
+        .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
+    let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value());
+    let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX);
+    let _ = 1i8.checked_sub(-1).unwrap_or(127);
+    let _ = 1i128
+        .checked_sub(-1)
+        .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727);
+    let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok
+    let _ = 1i8.checked_sub(1).unwrap_or(127); // ok
+    let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok
+}
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr
new file mode 100644
index 00000000000..d985f2e754b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr
@@ -0,0 +1,163 @@
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:8:13
+   |
+LL |     let _ = 1u32.checked_add(1).unwrap_or(u32::max_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)`
+   |
+   = note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:9:13
+   |
+LL |     let _ = 1u32.checked_add(1).unwrap_or(u32::MAX);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:10:13
+   |
+LL |     let _ = 1u8.checked_add(1).unwrap_or(255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u8.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:11:13
+   |
+LL |       let _ = 1u128
+   |  _____________^
+LL | |         .checked_add(1)
+LL | |         .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455);
+   | |_______________________________________________________________________^ help: try using `saturating_add`: `1u128.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:16:13
+   |
+LL |     let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_mul`: `1u32.saturating_mul(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:18:13
+   |
+LL |     let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:19:13
+   |
+LL |     let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:20:13
+   |
+LL |     let _ = 1u8.checked_sub(1).unwrap_or(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u8.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:24:13
+   |
+LL |     let _ = 1i32.checked_add(1).unwrap_or(i32::max_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:25:13
+   |
+LL |     let _ = 1i32.checked_add(1).unwrap_or(i32::MAX);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:26:13
+   |
+LL |     let _ = 1i8.checked_add(1).unwrap_or(127);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:27:13
+   |
+LL |       let _ = 1i128
+   |  _____________^
+LL | |         .checked_add(1)
+LL | |         .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727);
+   | |_______________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:30:13
+   |
+LL |     let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:31:13
+   |
+LL |     let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:32:13
+   |
+LL |     let _ = 1i8.checked_add(-1).unwrap_or(-128);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:33:13
+   |
+LL |       let _ = 1i128
+   |  _____________^
+LL | |         .checked_add(-1)
+LL | |         .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
+   | |________________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:40:13
+   |
+LL |     let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:41:13
+   |
+LL |     let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:42:13
+   |
+LL |     let _ = 1i8.checked_sub(1).unwrap_or(-128);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:43:13
+   |
+LL |       let _ = 1i128
+   |  _____________^
+LL | |         .checked_sub(1)
+LL | |         .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
+   | |________________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:46:13
+   |
+LL |     let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:47:13
+   |
+LL |     let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:48:13
+   |
+LL |     let _ = 1i8.checked_sub(-1).unwrap_or(127);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(-1)`
+
+error: manual saturating arithmetic
+  --> $DIR/manual_saturating_arithmetic.rs:49:13
+   |
+LL |       let _ = 1i128
+   |  _____________^
+LL | |         .checked_sub(-1)
+LL | |         .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727);
+   | |_______________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(-1)`
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/many_single_char_names.rs b/src/tools/clippy/tests/ui/many_single_char_names.rs
new file mode 100644
index 00000000000..80800e48724
--- /dev/null
+++ b/src/tools/clippy/tests/ui/many_single_char_names.rs
@@ -0,0 +1,73 @@
+#[warn(clippy::many_single_char_names)]
+
+fn bla() {
+    let a: i32;
+    let (b, c, d): (i32, i64, i16);
+    {
+        {
+            let cdefg: i32;
+            let blar: i32;
+        }
+        {
+            let e: i32;
+        }
+        {
+            let e: i32;
+            let f: i32;
+        }
+        match 5 {
+            1 => println!(),
+            e => panic!(),
+        }
+        match 5 {
+            1 => println!(),
+            _ => panic!(),
+        }
+    }
+}
+
+fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
+
+fn bindings2() {
+    let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!();
+}
+
+fn shadowing() {
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    {
+        let a = 0i32;
+    }
+}
+
+fn patterns() {
+    enum Z {
+        A(i32),
+        B(i32),
+        C(i32),
+        D(i32),
+        E(i32),
+        F(i32),
+    }
+
+    // These should not trigger a warning, since the pattern bindings are a new scope.
+    match Z::A(0) {
+        Z::A(a) => {},
+        Z::B(b) => {},
+        Z::C(c) => {},
+        Z::D(d) => {},
+        Z::E(e) => {},
+        Z::F(f) => {},
+    }
+}
+
+#[allow(clippy::many_single_char_names)]
+fn issue_3198_allow_works() {
+    let (a, b, c, d, e) = (0, 0, 0, 0, 0);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/many_single_char_names.stderr b/src/tools/clippy/tests/ui/many_single_char_names.stderr
new file mode 100644
index 00000000000..27e62e641ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/many_single_char_names.stderr
@@ -0,0 +1,51 @@
+error: 5 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             let e: i32;
+   |                 ^
+   |
+   = note: `-D clippy::many-single-char-names` implied by `-D warnings`
+
+error: 6 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             let e: i32;
+   |                 ^
+LL |             let f: i32;
+   |                 ^
+
+error: 5 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             e => panic!(),
+   |             ^
+
+error: 8 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:29:13
+   |
+LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
+   |             ^       ^       ^       ^       ^       ^       ^       ^
+
+error: 8 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:32:10
+   |
+LL |     let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!();
+   |          ^  ^  ^  ^  ^  ^  ^  ^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed
new file mode 100644
index 00000000000..81c7f659efb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_clone.fixed
@@ -0,0 +1,47 @@
+// run-rustfix
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::iter_cloned_collect)]
+#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
+#![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::redundant_closure_for_method_calls)]
+#![allow(clippy::many_single_char_names)]
+
+fn main() {
+    let _: Vec<i8> = vec![5_i8; 6].iter().copied().collect();
+    let _: Vec<String> = vec![String::new()].iter().cloned().collect();
+    let _: Vec<u32> = vec![42, 43].iter().copied().collect();
+    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
+    let _: Option<u64> = Some(&16).copied();
+    let _: Option<u8> = Some(&1).copied();
+
+    // Don't lint these
+    let v = vec![5_i8; 6];
+    let a = 0;
+    let b = &a;
+    let _ = v.iter().map(|_x| *b);
+    let _ = v.iter().map(|_x| a.clone());
+    let _ = v.iter().map(|&_x| a);
+
+    // Issue #498
+    let _ = std::env::args();
+
+    // Issue #4824 item types that aren't references
+    {
+        use std::rc::Rc;
+
+        let o: Option<Rc<u32>> = Some(Rc::new(0_u32));
+        let _: Option<u32> = o.map(|x| *x);
+        let v: Vec<Rc<u32>> = vec![Rc::new(0_u32)];
+        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
+    }
+
+    // Issue #5524 mutable references
+    {
+        let mut c = 42;
+        let v = vec![&mut c];
+        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
+        let mut d = 21;
+        let v = vec![&mut d];
+        let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs
new file mode 100644
index 00000000000..8ed164f0ed5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_clone.rs
@@ -0,0 +1,47 @@
+// run-rustfix
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::iter_cloned_collect)]
+#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
+#![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::redundant_closure_for_method_calls)]
+#![allow(clippy::many_single_char_names)]
+
+fn main() {
+    let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
+    let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
+    let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
+    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
+    let _: Option<u64> = Some(&16).map(|b| *b);
+    let _: Option<u8> = Some(&1).map(|x| x.clone());
+
+    // Don't lint these
+    let v = vec![5_i8; 6];
+    let a = 0;
+    let b = &a;
+    let _ = v.iter().map(|_x| *b);
+    let _ = v.iter().map(|_x| a.clone());
+    let _ = v.iter().map(|&_x| a);
+
+    // Issue #498
+    let _ = std::env::args().map(|v| v.clone());
+
+    // Issue #4824 item types that aren't references
+    {
+        use std::rc::Rc;
+
+        let o: Option<Rc<u32>> = Some(Rc::new(0_u32));
+        let _: Option<u32> = o.map(|x| *x);
+        let v: Vec<Rc<u32>> = vec![Rc::new(0_u32)];
+        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
+    }
+
+    // Issue #5524 mutable references
+    {
+        let mut c = 42;
+        let v = vec![&mut c];
+        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
+        let mut d = 21;
+        let v = vec![&mut d];
+        let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr
new file mode 100644
index 00000000000..9eec6928e8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_clone.stderr
@@ -0,0 +1,40 @@
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:10:22
+   |
+LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
+   |
+   = note: `-D clippy::map-clone` implied by `-D warnings`
+
+error: You are using an explicit closure for cloning elements
+  --> $DIR/map_clone.rs:11:26
+   |
+LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
+
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:12:23
+   |
+LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
+
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:14:26
+   |
+LL |     let _: Option<u64> = Some(&16).map(|b| *b);
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&16).copied()`
+
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:15:25
+   |
+LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&1).copied()`
+
+error: You are needlessly cloning iterator elements
+  --> $DIR/map_clone.rs:26:29
+   |
+LL |     let _ = std::env::args().map(|v| v.clone());
+   |                             ^^^^^^^^^^^^^^^^^^^ help: Remove the `map` call
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_flatten.fixed b/src/tools/clippy/tests/ui/map_flatten.fixed
new file mode 100644
index 00000000000..7ac368878ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_flatten.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::missing_docs_in_private_items)]
+
+fn main() {
+    let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
+    let _: Option<_> = (Some(Some(1))).and_then(|x| x);
+}
diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs
new file mode 100644
index 00000000000..a608601039c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_flatten.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::missing_docs_in_private_items)]
+
+fn main() {
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+    let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
+}
diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr
new file mode 100644
index 00000000000..3cf2abd5b6d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_flatten.stderr
@@ -0,0 +1,16 @@
+error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
+  --> $DIR/map_flatten.rs:7:21
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
+   |
+   = note: `-D clippy::map-flatten` implied by `-D warnings`
+
+error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)`
+  --> $DIR/map_flatten.rs:8:24
+   |
+LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_unit_fn.rs b/src/tools/clippy/tests/ui/map_unit_fn.rs
new file mode 100644
index 00000000000..9a74da4e3b8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_unit_fn.rs
@@ -0,0 +1,11 @@
+#![allow(unused)]
+struct Mappable {}
+
+impl Mappable {
+    pub fn map(&self) {}
+}
+
+fn main() {
+    let m = Mappable {};
+    m.map();
+}
diff --git a/src/tools/clippy/tests/ui/match_as_ref.fixed b/src/tools/clippy/tests/ui/match_as_ref.fixed
new file mode 100644
index 00000000000..c61eb921664
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_as_ref.fixed
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::match_as_ref)]
+
+fn match_as_ref() {
+    let owned: Option<()> = None;
+    let borrowed: Option<&()> = owned.as_ref();
+
+    let mut mut_owned: Option<()> = None;
+    let borrow_mut: Option<&mut ()> = mut_owned.as_mut();
+}
+
+mod issue4437 {
+    use std::{error::Error, fmt, num::ParseIntError};
+
+    #[derive(Debug)]
+    struct E {
+        source: Option<ParseIntError>,
+    }
+
+    impl Error for E {
+        fn source(&self) -> Option<&(dyn Error + 'static)> {
+            self.source.as_ref().map(|x| x as _)
+        }
+    }
+
+    impl fmt::Display for E {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            unimplemented!()
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs
new file mode 100644
index 00000000000..2fbd0b255fa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_as_ref.rs
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::match_as_ref)]
+
+fn match_as_ref() {
+    let owned: Option<()> = None;
+    let borrowed: Option<&()> = match owned {
+        None => None,
+        Some(ref v) => Some(v),
+    };
+
+    let mut mut_owned: Option<()> = None;
+    let borrow_mut: Option<&mut ()> = match mut_owned {
+        None => None,
+        Some(ref mut v) => Some(v),
+    };
+}
+
+mod issue4437 {
+    use std::{error::Error, fmt, num::ParseIntError};
+
+    #[derive(Debug)]
+    struct E {
+        source: Option<ParseIntError>,
+    }
+
+    impl Error for E {
+        fn source(&self) -> Option<&(dyn Error + 'static)> {
+            match self.source {
+                Some(ref s) => Some(s),
+                None => None,
+            }
+        }
+    }
+
+    impl fmt::Display for E {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            unimplemented!()
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_as_ref.stderr b/src/tools/clippy/tests/ui/match_as_ref.stderr
new file mode 100644
index 00000000000..c3b62849cb3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_as_ref.stderr
@@ -0,0 +1,33 @@
+error: use `as_ref()` instead
+  --> $DIR/match_as_ref.rs:8:33
+   |
+LL |       let borrowed: Option<&()> = match owned {
+   |  _________________________________^
+LL | |         None => None,
+LL | |         Some(ref v) => Some(v),
+LL | |     };
+   | |_____^ help: try this: `owned.as_ref()`
+   |
+   = note: `-D clippy::match-as-ref` implied by `-D warnings`
+
+error: use `as_mut()` instead
+  --> $DIR/match_as_ref.rs:14:39
+   |
+LL |       let borrow_mut: Option<&mut ()> = match mut_owned {
+   |  _______________________________________^
+LL | |         None => None,
+LL | |         Some(ref mut v) => Some(v),
+LL | |     };
+   | |_____^ help: try this: `mut_owned.as_mut()`
+
+error: use `as_ref()` instead
+  --> $DIR/match_as_ref.rs:30:13
+   |
+LL | /             match self.source {
+LL | |                 Some(ref s) => Some(s),
+LL | |                 None => None,
+LL | |             }
+   | |_____________^ help: try this: `self.source.as_ref().map(|x| x as _)`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs
new file mode 100644
index 00000000000..9ed55ca7ae7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_bool.rs
@@ -0,0 +1,55 @@
+#![deny(clippy::match_bool)]
+
+fn match_bool() {
+    let test: bool = true;
+
+    match test {
+        true => 0,
+        false => 42,
+    };
+
+    let option = 1;
+    match option == 1 {
+        true => 1,
+        false => 0,
+    };
+
+    match test {
+        true => (),
+        false => {
+            println!("Noooo!");
+        },
+    };
+
+    match test {
+        false => {
+            println!("Noooo!");
+        },
+        _ => (),
+    };
+
+    match test && test {
+        false => {
+            println!("Noooo!");
+        },
+        _ => (),
+    };
+
+    match test {
+        false => {
+            println!("Noooo!");
+        },
+        true => {
+            println!("Yes!");
+        },
+    };
+
+    // Not linted
+    match option {
+        1..=10 => 1,
+        11..=20 => 2,
+        _ => 3,
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_bool.stderr b/src/tools/clippy/tests/ui/match_bool.stderr
new file mode 100644
index 00000000000..1ad78c740c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_bool.stderr
@@ -0,0 +1,117 @@
+error: this boolean expression can be simplified
+  --> $DIR/match_bool.rs:31:11
+   |
+LL |     match test && test {
+   |           ^^^^^^^^^^^^ help: try: `test`
+   |
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:6:5
+   |
+LL | /     match test {
+LL | |         true => 0,
+LL | |         false => 42,
+LL | |     };
+   | |_____^ help: consider using an `if`/`else` expression: `if test { 0 } else { 42 }`
+   |
+note: the lint level is defined here
+  --> $DIR/match_bool.rs:1:9
+   |
+LL | #![deny(clippy::match_bool)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:12:5
+   |
+LL | /     match option == 1 {
+LL | |         true => 1,
+LL | |         false => 0,
+LL | |     };
+   | |_____^ help: consider using an `if`/`else` expression: `if option == 1 { 1 } else { 0 }`
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:17:5
+   |
+LL | /     match test {
+LL | |         true => (),
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |     };
+   | |_____^
+   |
+help: consider using an `if`/`else` expression
+   |
+LL |     if !test {
+LL |         println!("Noooo!");
+LL |     };
+   |
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:24:5
+   |
+LL | /     match test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
+   |
+help: consider using an `if`/`else` expression
+   |
+LL |     if !test {
+LL |         println!("Noooo!");
+LL |     };
+   |
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:31:5
+   |
+LL | /     match test && test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
+   |
+help: consider using an `if`/`else` expression
+   |
+LL |     if !(test && test) {
+LL |         println!("Noooo!");
+LL |     };
+   |
+
+error: equal expressions as operands to `&&`
+  --> $DIR/match_bool.rs:31:11
+   |
+LL |     match test && test {
+   |           ^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::eq_op)]` on by default
+
+error: you seem to be trying to match on a boolean expression
+  --> $DIR/match_bool.rs:38:5
+   |
+LL | /     match test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+...  |
+LL | |         },
+LL | |     };
+   | |_____^
+   |
+help: consider using an `if`/`else` expression
+   |
+LL |     if test {
+LL |         println!("Yes!");
+LL |     } else {
+LL |         println!("Noooo!");
+LL |     };
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.rs b/src/tools/clippy/tests/ui/match_on_vec_items.rs
new file mode 100644
index 00000000000..0bb39d77e46
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_on_vec_items.rs
@@ -0,0 +1,130 @@
+#![warn(clippy::match_on_vec_items)]
+
+fn match_with_wildcard() {
+    let arr = vec![0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 1;
+
+    // Lint, may panic
+    match arr[idx] {
+        0 => println!("0"),
+        1 => println!("1"),
+        _ => {},
+    }
+
+    // Lint, may panic
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        _ => {},
+    }
+}
+
+fn match_without_wildcard() {
+    let arr = vec![0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 2;
+
+    // Lint, may panic
+    match arr[idx] {
+        0 => println!("0"),
+        1 => println!("1"),
+        num => {},
+    }
+
+    // Lint, may panic
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        [ref sub @ ..] => {},
+    }
+}
+
+fn match_wildcard_and_action() {
+    let arr = vec![0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 3;
+
+    // Lint, may panic
+    match arr[idx] {
+        0 => println!("0"),
+        1 => println!("1"),
+        _ => println!("Hello, World!"),
+    }
+
+    // Lint, may panic
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        _ => println!("Hello, World!"),
+    }
+}
+
+fn match_vec_ref() {
+    let arr = &vec![0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 3;
+
+    // Lint, may panic
+    match arr[idx] {
+        0 => println!("0"),
+        1 => println!("1"),
+        _ => {},
+    }
+
+    // Lint, may panic
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        _ => {},
+    }
+}
+
+fn match_with_get() {
+    let arr = vec![0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 3;
+
+    // Ok
+    match arr.get(idx) {
+        Some(0) => println!("0"),
+        Some(1) => println!("1"),
+        _ => {},
+    }
+
+    // Ok
+    match arr.get(range) {
+        Some(&[0, 1]) => println!("0 1"),
+        Some(&[1, 2]) => println!("1 2"),
+        _ => {},
+    }
+}
+
+fn match_with_array() {
+    let arr = [0, 1, 2, 3];
+    let range = 1..3;
+    let idx = 3;
+
+    // Ok
+    match arr[idx] {
+        0 => println!("0"),
+        1 => println!("1"),
+        _ => {},
+    }
+
+    // Ok
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        _ => {},
+    }
+}
+
+fn main() {
+    match_with_wildcard();
+    match_without_wildcard();
+    match_wildcard_and_action();
+    match_vec_ref();
+    match_with_get();
+    match_with_array();
+}
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.stderr b/src/tools/clippy/tests/ui/match_on_vec_items.stderr
new file mode 100644
index 00000000000..49446d715ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_on_vec_items.stderr
@@ -0,0 +1,52 @@
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:9:11
+   |
+LL |     match arr[idx] {
+   |           ^^^^^^^^ help: try this: `arr.get(idx)`
+   |
+   = note: `-D clippy::match-on-vec-items` implied by `-D warnings`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:16:11
+   |
+LL |     match arr[range] {
+   |           ^^^^^^^^^^ help: try this: `arr.get(range)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:29:11
+   |
+LL |     match arr[idx] {
+   |           ^^^^^^^^ help: try this: `arr.get(idx)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:36:11
+   |
+LL |     match arr[range] {
+   |           ^^^^^^^^^^ help: try this: `arr.get(range)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:49:11
+   |
+LL |     match arr[idx] {
+   |           ^^^^^^^^ help: try this: `arr.get(idx)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:56:11
+   |
+LL |     match arr[range] {
+   |           ^^^^^^^^^^ help: try this: `arr.get(range)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:69:11
+   |
+LL |     match arr[idx] {
+   |           ^^^^^^^^ help: try this: `arr.get(idx)`
+
+error: indexing into a vector may panic
+  --> $DIR/match_on_vec_items.rs:76:11
+   |
+LL |     match arr[range] {
+   |           ^^^^^^^^^^ help: try this: `arr.get(range)`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
new file mode 100644
index 00000000000..97789bb766f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
@@ -0,0 +1,82 @@
+#![feature(exclusive_range_pattern)]
+#![feature(half_open_range_patterns)]
+#![warn(clippy::match_overlapping_arm)]
+#![allow(clippy::redundant_pattern_matching)]
+
+/// Tests for match_overlapping_arm
+
+fn overlapping() {
+    const FOO: u64 = 2;
+
+    match 42 {
+        0..=10 => println!("0 ... 10"),
+        0..=11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    match 42 {
+        0..=5 => println!("0 ... 5"),
+        6..=7 => println!("6 ... 7"),
+        FOO..=11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0..=5 => println!("0 ... 5"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0..=2 => println!("0 ... 2"),
+        _ => (),
+    }
+
+    match 42 {
+        0..=10 => println!("0 ... 10"),
+        11..=50 => println!("11 ... 50"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0..2 => println!("0 .. 2"),
+        _ => (),
+    }
+
+    match 42 {
+        0..10 => println!("0 .. 10"),
+        10..50 => println!("10 .. 50"),
+        _ => (),
+    }
+
+    match 42 {
+        0..11 => println!("0 .. 11"),
+        0..=11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    /*
+    // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
+    match 42 {
+        0.. => println!("0 .. 42"),
+        3.. => println!("3 .. 42"),
+        _ => (),
+    }
+
+    match 42 {
+        ..=23 => println!("0 ... 23"),
+        ..26 => println!("0 .. 26"),
+        _ => (),
+    }
+    */
+
+    if let None = Some(42) {
+        // nothing
+    } else if let None = Some(42) {
+        // another nothing :-)
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
new file mode 100644
index 00000000000..eb20d5405a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
@@ -0,0 +1,63 @@
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:12:9
+   |
+LL |         0..=10 => println!("0 ... 10"),
+   |         ^^^^^^
+   |
+   = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:13:9
+   |
+LL |         0..=11 => println!("0 ... 11"),
+   |         ^^^^^^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:18:9
+   |
+LL |         0..=5 => println!("0 ... 5"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:20:9
+   |
+LL |         FOO..=11 => println!("0 ... 11"),
+   |         ^^^^^^^^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:26:9
+   |
+LL |         0..=5 => println!("0 ... 5"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:25:9
+   |
+LL |         2 => println!("2"),
+   |         ^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:32:9
+   |
+LL |         0..=2 => println!("0 ... 2"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:31:9
+   |
+LL |         2 => println!("2"),
+   |         ^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:55:9
+   |
+LL |         0..11 => println!("0 .. 11"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:56:9
+   |
+LL |         0..=11 => println!("0 ... 11"),
+   |         ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs
new file mode 100644
index 00000000000..5de43733ad3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_ref_pats.rs
@@ -0,0 +1,74 @@
+#![warn(clippy::match_ref_pats)]
+
+fn ref_pats() {
+    {
+        let v = &Some(0);
+        match v {
+            &Some(v) => println!("{:?}", v),
+            &None => println!("none"),
+        }
+        match v {
+            // This doesn't trigger; we have a different pattern.
+            &Some(v) => println!("some"),
+            other => println!("other"),
+        }
+    }
+    let tup = &(1, 2);
+    match tup {
+        &(v, 1) => println!("{}", v),
+        _ => println!("none"),
+    }
+    // Special case: using `&` both in expr and pats.
+    let w = Some(0);
+    match &w {
+        &Some(v) => println!("{:?}", v),
+        &None => println!("none"),
+    }
+    // False positive: only wildcard pattern.
+    let w = Some(0);
+    #[allow(clippy::match_single_binding)]
+    match w {
+        _ => println!("none"),
+    }
+
+    let a = &Some(0);
+    if let &None = a {
+        println!("none");
+    }
+
+    let b = Some(0);
+    if let &None = &b {
+        println!("none");
+    }
+}
+
+mod ice_3719 {
+    macro_rules! foo_variant(
+        ($idx:expr) => (Foo::get($idx).unwrap())
+    );
+
+    enum Foo {
+        A,
+        B,
+    }
+
+    impl Foo {
+        fn get(idx: u8) -> Option<&'static Self> {
+            match idx {
+                0 => Some(&Foo::A),
+                1 => Some(&Foo::B),
+                _ => None,
+            }
+        }
+    }
+
+    fn ice_3719() {
+        // ICE #3719
+        match foo_variant!(0) {
+            &Foo::A => println!("A"),
+            _ => println!("Wild"),
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr
new file mode 100644
index 00000000000..52cb4a14b72
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr
@@ -0,0 +1,91 @@
+error: you don't need to add `&` to all patterns
+  --> $DIR/match_ref_pats.rs:6:9
+   |
+LL | /         match v {
+LL | |             &Some(v) => println!("{:?}", v),
+LL | |             &None => println!("none"),
+LL | |         }
+   | |_________^
+   |
+   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
+help: instead of prefixing all patterns with `&`, you can dereference the expression
+   |
+LL |         match *v {
+LL |             Some(v) => println!("{:?}", v),
+LL |             None => println!("none"),
+   |
+
+error: you don't need to add `&` to all patterns
+  --> $DIR/match_ref_pats.rs:17:5
+   |
+LL | /     match tup {
+LL | |         &(v, 1) => println!("{}", v),
+LL | |         _ => println!("none"),
+LL | |     }
+   | |_____^
+   |
+help: instead of prefixing all patterns with `&`, you can dereference the expression
+   |
+LL |     match *tup {
+LL |         (v, 1) => println!("{}", v),
+   |
+
+error: you don't need to add `&` to both the expression and the patterns
+  --> $DIR/match_ref_pats.rs:23:5
+   |
+LL | /     match &w {
+LL | |         &Some(v) => println!("{:?}", v),
+LL | |         &None => println!("none"),
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     match w {
+LL |         Some(v) => println!("{:?}", v),
+LL |         None => println!("none"),
+   |
+
+error: you don't need to add `&` to all patterns
+  --> $DIR/match_ref_pats.rs:35:5
+   |
+LL | /     if let &None = a {
+LL | |         println!("none");
+LL | |     }
+   | |_____^
+   |
+help: instead of prefixing all patterns with `&`, you can dereference the expression
+   |
+LL |     if let None = *a {
+   |            ^^^^   ^^
+
+error: you don't need to add `&` to both the expression and the patterns
+  --> $DIR/match_ref_pats.rs:40:5
+   |
+LL | /     if let &None = &b {
+LL | |         println!("none");
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     if let None = b {
+   |            ^^^^   ^
+
+error: you don't need to add `&` to all patterns
+  --> $DIR/match_ref_pats.rs:67:9
+   |
+LL | /         match foo_variant!(0) {
+LL | |             &Foo::A => println!("A"),
+LL | |             _ => println!("Wild"),
+LL | |         }
+   | |_________^
+   |
+help: instead of prefixing all patterns with `&`, you can dereference the expression
+   |
+LL |         match *foo_variant!(0) {
+LL |             Foo::A => println!("A"),
+   |
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs
new file mode 100644
index 00000000000..0b9342c9c42
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms.rs
@@ -0,0 +1,56 @@
+#![warn(clippy::match_same_arms)]
+
+pub enum Abc {
+    A,
+    B,
+    C,
+}
+
+fn match_same_arms() {
+    let _ = match Abc::A {
+        Abc::A => 0,
+        Abc::B => 1,
+        _ => 0, //~ ERROR match arms have same body
+    };
+
+    match (1, 2, 3) {
+        (1, .., 3) => 42,
+        (.., 3) => 42, //~ ERROR match arms have same body
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        42 => 1,
+        51 => 1, //~ ERROR match arms have same body
+        41 => 2,
+        52 => 2, //~ ERROR match arms have same body
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        1 => 2,
+        2 => 2, //~ ERROR 2nd matched arms have same body
+        3 => 2, //~ ERROR 3rd matched arms have same body
+        4 => 3,
+        _ => 0,
+    };
+}
+
+mod issue4244 {
+    #[derive(PartialEq, PartialOrd, Eq, Ord)]
+    pub enum CommandInfo {
+        BuiltIn { name: String, about: Option<String> },
+        External { name: String, path: std::path::PathBuf },
+    }
+
+    impl CommandInfo {
+        pub fn name(&self) -> String {
+            match self {
+                CommandInfo::BuiltIn { name, .. } => name.to_string(),
+                CommandInfo::External { name, .. } => name.to_string(),
+            }
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
new file mode 100644
index 00000000000..0549886a1e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -0,0 +1,139 @@
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:13:14
+   |
+LL |         _ => 0, //~ ERROR match arms have same body
+   |              ^
+   |
+   = note: `-D clippy::match-same-arms` implied by `-D warnings`
+note: same as this
+  --> $DIR/match_same_arms.rs:11:19
+   |
+LL |         Abc::A => 0,
+   |                   ^
+note: `Abc::A` has the same arm body as the `_` wildcard, consider removing it
+  --> $DIR/match_same_arms.rs:11:19
+   |
+LL |         Abc::A => 0,
+   |                   ^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:18:20
+   |
+LL |         (.., 3) => 42, //~ ERROR match arms have same body
+   |                    ^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:17:23
+   |
+LL |         (1, .., 3) => 42,
+   |                       ^^
+help: consider refactoring into `(1, .., 3) | (.., 3)`
+  --> $DIR/match_same_arms.rs:17:9
+   |
+LL |         (1, .., 3) => 42,
+   |         ^^^^^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:24:15
+   |
+LL |         51 => 1, //~ ERROR match arms have same body
+   |               ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:23:15
+   |
+LL |         42 => 1,
+   |               ^
+help: consider refactoring into `42 | 51`
+  --> $DIR/match_same_arms.rs:23:9
+   |
+LL |         42 => 1,
+   |         ^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:26:15
+   |
+LL |         52 => 2, //~ ERROR match arms have same body
+   |               ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:25:15
+   |
+LL |         41 => 2,
+   |               ^
+help: consider refactoring into `41 | 52`
+  --> $DIR/match_same_arms.rs:25:9
+   |
+LL |         41 => 2,
+   |         ^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:32:14
+   |
+LL |         2 => 2, //~ ERROR 2nd matched arms have same body
+   |              ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:31:14
+   |
+LL |         1 => 2,
+   |              ^
+help: consider refactoring into `1 | 2`
+  --> $DIR/match_same_arms.rs:31:9
+   |
+LL |         1 => 2,
+   |         ^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:33:14
+   |
+LL |         3 => 2, //~ ERROR 3rd matched arms have same body
+   |              ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:31:14
+   |
+LL |         1 => 2,
+   |              ^
+help: consider refactoring into `1 | 3`
+  --> $DIR/match_same_arms.rs:31:9
+   |
+LL |         1 => 2,
+   |         ^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:33:14
+   |
+LL |         3 => 2, //~ ERROR 3rd matched arms have same body
+   |              ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:32:14
+   |
+LL |         2 => 2, //~ ERROR 2nd matched arms have same body
+   |              ^
+help: consider refactoring into `2 | 3`
+  --> $DIR/match_same_arms.rs:32:9
+   |
+LL |         2 => 2, //~ ERROR 2nd matched arms have same body
+   |         ^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:50:55
+   |
+LL |                 CommandInfo::External { name, .. } => name.to_string(),
+   |                                                       ^^^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:49:54
+   |
+LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                                                      ^^^^^^^^^^^^^^^^
+help: consider refactoring into `CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. }`
+  --> $DIR/match_same_arms.rs:49:17
+   |
+LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
new file mode 100644
index 00000000000..e1401d2796a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -0,0 +1,124 @@
+#![warn(clippy::match_same_arms)]
+#![allow(clippy::blacklisted_name)]
+
+fn bar<T>(_: T) {}
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn match_same_arms() {
+    let _ = match 42 {
+        42 => {
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+        _ => {
+            //~ ERROR match arms have same body
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+    };
+
+    let _ = match 42 {
+        42 => foo(),
+        51 => foo(), //~ ERROR match arms have same body
+        _ => true,
+    };
+
+    let _ = match Some(42) {
+        Some(_) => 24,
+        None => 24, //~ ERROR match arms have same body
+    };
+
+    let _ = match Some(42) {
+        Some(foo) => 24,
+        None => 24,
+    };
+
+    let _ = match Some(42) {
+        Some(42) => 24,
+        Some(a) => 24, // bindings are different
+        None => 0,
+    };
+
+    let _ = match Some(42) {
+        Some(a) if a > 0 => 24,
+        Some(a) => 24, // one arm has a guard
+        None => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), //~ ERROR match arms have same body
+        _ => (),
+    }
+
+    match (Some(42), Some(42)) {
+        (Some(a), ..) => bar(a),
+        (.., Some(a)) => bar(a), //~ ERROR match arms have same body
+        _ => (),
+    }
+
+    let _ = match Some(()) {
+        Some(()) => 0.0,
+        None => -0.0,
+    };
+
+    match (Some(42), Some("")) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), // bindings have different types
+        _ => (),
+    }
+
+    let x: Result<i32, &str> = Ok(3);
+
+    // No warning because of the guard.
+    match x {
+        Ok(x) if x * x == 64 => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    // This used to be a false positive; see issue #1996.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(x) if x * x == 64 => println!("ok 64"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    match (x, Some(1i32)) {
+        (Ok(x), Some(_)) => println!("ok {}", x),
+        (Ok(_), Some(x)) => println!("ok {}", x),
+        _ => println!("err"),
+    }
+
+    // No warning; different types for `x`.
+    match (x, Some(1.0f64)) {
+        (Ok(x), Some(_)) => println!("ok {}", x),
+        (Ok(_), Some(x)) => println!("ok {}", x),
+        _ => println!("err"),
+    }
+
+    // False negative #2251.
+    match x {
+        Ok(_tmp) => println!("ok"),
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => {
+            unreachable!();
+        },
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
new file mode 100644
index 00000000000..26c65f32ad7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -0,0 +1,145 @@
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:20:14
+   |
+LL |           _ => {
+   |  ______________^
+LL | |             //~ ERROR match arms have same body
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+   |
+   = note: `-D clippy::match-same-arms` implied by `-D warnings`
+note: same as this
+  --> $DIR/match_same_arms2.rs:11:15
+   |
+LL |           42 => {
+   |  _______________^
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+LL | |             if true {
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+note: `42` has the same arm body as the `_` wildcard, consider removing it
+  --> $DIR/match_same_arms2.rs:11:15
+   |
+LL |           42 => {
+   |  _______________^
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+LL | |             if true {
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:34:15
+   |
+LL |         51 => foo(), //~ ERROR match arms have same body
+   |               ^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:33:15
+   |
+LL |         42 => foo(),
+   |               ^^^^^
+help: consider refactoring into `42 | 51`
+  --> $DIR/match_same_arms2.rs:33:9
+   |
+LL |         42 => foo(),
+   |         ^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:40:17
+   |
+LL |         None => 24, //~ ERROR match arms have same body
+   |                 ^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:39:20
+   |
+LL |         Some(_) => 24,
+   |                    ^^
+help: consider refactoring into `Some(_) | None`
+  --> $DIR/match_same_arms2.rs:39:9
+   |
+LL |         Some(_) => 24,
+   |         ^^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:62:28
+   |
+LL |         (None, Some(a)) => bar(a), //~ ERROR match arms have same body
+   |                            ^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:61:28
+   |
+LL |         (Some(a), None) => bar(a),
+   |                            ^^^^^^
+help: consider refactoring into `(Some(a), None) | (None, Some(a))`
+  --> $DIR/match_same_arms2.rs:61:9
+   |
+LL |         (Some(a), None) => bar(a),
+   |         ^^^^^^^^^^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:68:26
+   |
+LL |         (.., Some(a)) => bar(a), //~ ERROR match arms have same body
+   |                          ^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:67:26
+   |
+LL |         (Some(a), ..) => bar(a),
+   |                          ^^^^^^
+help: consider refactoring into `(Some(a), ..) | (.., Some(a))`
+  --> $DIR/match_same_arms2.rs:67:9
+   |
+LL |         (Some(a), ..) => bar(a),
+   |         ^^^^^^^^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:102:29
+   |
+LL |         (Ok(_), Some(x)) => println!("ok {}", x),
+   |                             ^^^^^^^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:101:29
+   |
+LL |         (Ok(x), Some(_)) => println!("ok {}", x),
+   |                             ^^^^^^^^^^^^^^^^^^^^
+help: consider refactoring into `(Ok(x), Some(_)) | (Ok(_), Some(x))`
+  --> $DIR/match_same_arms2.rs:101:9
+   |
+LL |         (Ok(x), Some(_)) => println!("ok {}", x),
+   |         ^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms2.rs:117:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms2.rs:116:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+help: consider refactoring into `Ok(3) | Ok(_)`
+  --> $DIR/match_same_arms2.rs:116:9
+   |
+LL |         Ok(3) => println!("ok"),
+   |         ^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
new file mode 100644
index 00000000000..f3627902eec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -0,0 +1,90 @@
+// run-rustfix
+
+#![warn(clippy::match_single_binding)]
+#![allow(unused_variables, clippy::many_single_char_names, clippy::toplevel_ref_arg)]
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn coords() -> Point {
+    Point { x: 1, y: 2 }
+}
+
+macro_rules! foo {
+    ($param:expr) => {
+        match $param {
+            _ => println!("whatever"),
+        }
+    };
+}
+
+fn main() {
+    let a = 1;
+    let b = 2;
+    let c = 3;
+    // Lint
+    let (x, y, z) = (a, b, c);
+    {
+        println!("{} {} {}", x, y, z);
+    }
+    // Lint
+    let (x, y, z) = (a, b, c);
+    println!("{} {} {}", x, y, z);
+    // Ok
+    foo!(a);
+    // Ok
+    match a {
+        2 => println!("2"),
+        _ => println!("Not 2"),
+    }
+    // Ok
+    let d = Some(5);
+    match d {
+        Some(d) => println!("{}", d),
+        _ => println!("None"),
+    }
+    // Lint
+    println!("whatever");
+    // Lint
+    {
+        let x = 29;
+        println!("x has a value of {}", x);
+    }
+    // Lint
+    {
+        let e = 5 * a;
+        if e >= 5 {
+            println!("e is superior to 5");
+        }
+    }
+    // Lint
+    let p = Point { x: 0, y: 7 };
+    let Point { x, y } = p;
+    println!("Coords: ({}, {})", x, y);
+    // Lint
+    let Point { x: x1, y: y1 } = p;
+    println!("Coords: ({}, {})", x1, y1);
+    // Lint
+    let x = 5;
+    let ref r = x;
+    println!("Got a reference to {}", r);
+    // Lint
+    let mut x = 5;
+    let ref mut mr = x;
+    println!("Got a mutable reference to {}", mr);
+    // Lint
+    let Point { x, y } = coords();
+    let product = x * y;
+    // Lint
+    let v = vec![Some(1), Some(2), Some(3), Some(4)];
+    #[allow(clippy::let_and_return)]
+    let _ = v
+        .iter()
+        .map(|i| {
+            let unwrapped = i.unwrap();
+            unwrapped
+        })
+        .collect::<Vec<u8>>();
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
new file mode 100644
index 00000000000..8c182148ae1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -0,0 +1,102 @@
+// run-rustfix
+
+#![warn(clippy::match_single_binding)]
+#![allow(unused_variables, clippy::many_single_char_names, clippy::toplevel_ref_arg)]
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn coords() -> Point {
+    Point { x: 1, y: 2 }
+}
+
+macro_rules! foo {
+    ($param:expr) => {
+        match $param {
+            _ => println!("whatever"),
+        }
+    };
+}
+
+fn main() {
+    let a = 1;
+    let b = 2;
+    let c = 3;
+    // Lint
+    match (a, b, c) {
+        (x, y, z) => {
+            println!("{} {} {}", x, y, z);
+        },
+    }
+    // Lint
+    match (a, b, c) {
+        (x, y, z) => println!("{} {} {}", x, y, z),
+    }
+    // Ok
+    foo!(a);
+    // Ok
+    match a {
+        2 => println!("2"),
+        _ => println!("Not 2"),
+    }
+    // Ok
+    let d = Some(5);
+    match d {
+        Some(d) => println!("{}", d),
+        _ => println!("None"),
+    }
+    // Lint
+    match a {
+        _ => println!("whatever"),
+    }
+    // Lint
+    match a {
+        _ => {
+            let x = 29;
+            println!("x has a value of {}", x);
+        },
+    }
+    // Lint
+    match a {
+        _ => {
+            let e = 5 * a;
+            if e >= 5 {
+                println!("e is superior to 5");
+            }
+        },
+    }
+    // Lint
+    let p = Point { x: 0, y: 7 };
+    match p {
+        Point { x, y } => println!("Coords: ({}, {})", x, y),
+    }
+    // Lint
+    match p {
+        Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+    }
+    // Lint
+    let x = 5;
+    match x {
+        ref r => println!("Got a reference to {}", r),
+    }
+    // Lint
+    let mut x = 5;
+    match x {
+        ref mut mr => println!("Got a mutable reference to {}", mr),
+    }
+    // Lint
+    let product = match coords() {
+        Point { x, y } => x * y,
+    };
+    // Lint
+    let v = vec![Some(1), Some(2), Some(3), Some(4)];
+    #[allow(clippy::let_and_return)]
+    let _ = v
+        .iter()
+        .map(|i| match i.unwrap() {
+            unwrapped => unwrapped,
+        })
+        .collect::<Vec<u8>>();
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
new file mode 100644
index 00000000000..795c8c3e24d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -0,0 +1,171 @@
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:28:5
+   |
+LL | /     match (a, b, c) {
+LL | |         (x, y, z) => {
+LL | |             println!("{} {} {}", x, y, z);
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::match-single-binding` implied by `-D warnings`
+help: consider using `let` statement
+   |
+LL |     let (x, y, z) = (a, b, c);
+LL |     {
+LL |         println!("{} {} {}", x, y, z);
+LL |     }
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:34:5
+   |
+LL | /     match (a, b, c) {
+LL | |         (x, y, z) => println!("{} {} {}", x, y, z),
+LL | |     }
+   | |_____^
+   |
+help: consider using `let` statement
+   |
+LL |     let (x, y, z) = (a, b, c);
+LL |     println!("{} {} {}", x, y, z);
+   |
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:51:5
+   |
+LL | /     match a {
+LL | |         _ => println!("whatever"),
+LL | |     }
+   | |_____^ help: consider using the match body instead: `println!("whatever");`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:55:5
+   |
+LL | /     match a {
+LL | |         _ => {
+LL | |             let x = 29;
+LL | |             println!("x has a value of {}", x);
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: consider using the match body instead
+   |
+LL |     {
+LL |         let x = 29;
+LL |         println!("x has a value of {}", x);
+LL |     }
+   |
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:62:5
+   |
+LL | /     match a {
+LL | |         _ => {
+LL | |             let e = 5 * a;
+LL | |             if e >= 5 {
+...  |
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: consider using the match body instead
+   |
+LL |     {
+LL |         let e = 5 * a;
+LL |         if e >= 5 {
+LL |             println!("e is superior to 5");
+LL |         }
+LL |     }
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:72:5
+   |
+LL | /     match p {
+LL | |         Point { x, y } => println!("Coords: ({}, {})", x, y),
+LL | |     }
+   | |_____^
+   |
+help: consider using `let` statement
+   |
+LL |     let Point { x, y } = p;
+LL |     println!("Coords: ({}, {})", x, y);
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:76:5
+   |
+LL | /     match p {
+LL | |         Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+LL | |     }
+   | |_____^
+   |
+help: consider using `let` statement
+   |
+LL |     let Point { x: x1, y: y1 } = p;
+LL |     println!("Coords: ({}, {})", x1, y1);
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:81:5
+   |
+LL | /     match x {
+LL | |         ref r => println!("Got a reference to {}", r),
+LL | |     }
+   | |_____^
+   |
+help: consider using `let` statement
+   |
+LL |     let ref r = x;
+LL |     println!("Got a reference to {}", r);
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:86:5
+   |
+LL | /     match x {
+LL | |         ref mut mr => println!("Got a mutable reference to {}", mr),
+LL | |     }
+   | |_____^
+   |
+help: consider using `let` statement
+   |
+LL |     let ref mut mr = x;
+LL |     println!("Got a mutable reference to {}", mr);
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:90:5
+   |
+LL | /     let product = match coords() {
+LL | |         Point { x, y } => x * y,
+LL | |     };
+   | |______^
+   |
+help: consider using `let` statement
+   |
+LL |     let Point { x, y } = coords();
+LL |     let product = x * y;
+   |
+
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:98:18
+   |
+LL |           .map(|i| match i.unwrap() {
+   |  __________________^
+LL | |             unwrapped => unwrapped,
+LL | |         })
+   | |_________^
+   |
+help: consider using `let` statement
+   |
+LL |         .map(|i| {
+LL |             let unwrapped = i.unwrap();
+LL |             unwrapped
+LL |         })
+   |
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
new file mode 100644
index 00000000000..823be65efe0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
@@ -0,0 +1,65 @@
+#![feature(exclusive_range_pattern)]
+#![allow(clippy::match_same_arms)]
+#![warn(clippy::match_wild_err_arm)]
+
+fn match_wild_err_arm() {
+    let x: Result<i32, &str> = Ok(3);
+
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => panic!("err"),
+    }
+
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => panic!(),
+    }
+
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => {
+            panic!();
+        },
+    }
+
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_e) => panic!(),
+    }
+
+    // Allowed when used in `panic!`.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_e) => panic!("{}", _e),
+    }
+
+    // Allowed when not with `panic!` block.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    // Allowed when used with `unreachable!`.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => unreachable!(),
+    }
+
+    // Allowed when used with `unreachable!`.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => {
+            unreachable!();
+        },
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
new file mode 100644
index 00000000000..20d4c933418
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
@@ -0,0 +1,35 @@
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:11:9
+   |
+LL |         Err(_) => panic!("err"),
+   |         ^^^^^^
+   |
+   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+   = note: match each error separately or use the error output
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:17:9
+   |
+LL |         Err(_) => panic!(),
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:23:9
+   |
+LL |         Err(_) => {
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output
+
+error: `Err(_e)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:31:9
+   |
+LL |         Err(_e) => panic!(),
+   |         ^^^^^^^
+   |
+   = note: match each error separately or use the error output
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.fixed b/src/tools/clippy/tests/ui/mem_discriminant.fixed
new file mode 100644
index 00000000000..69a8f286d05
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_discriminant.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#![deny(clippy::mem_discriminant_non_enum)]
+
+use std::mem;
+
+enum Foo {
+    One(usize),
+    Two(u8),
+}
+
+fn main() {
+    // bad
+    mem::discriminant(&Some(2));
+    mem::discriminant(&None::<u8>);
+    mem::discriminant(&Foo::One(5));
+    mem::discriminant(&Foo::Two(5));
+
+    let ro = &Some(3);
+    let rro = &ro;
+    mem::discriminant(ro);
+    mem::discriminant(*rro);
+    mem::discriminant(*rro);
+
+    macro_rules! mem_discriminant_but_in_a_macro {
+        ($param:expr) => {
+            mem::discriminant($param)
+        };
+    }
+
+    mem_discriminant_but_in_a_macro!(*rro);
+
+    let rrrrro = &&&rro;
+    mem::discriminant(****rrrrro);
+    mem::discriminant(****rrrrro);
+
+    // ok
+    mem::discriminant(&Some(2));
+    mem::discriminant(&None::<u8>);
+    mem::discriminant(&Foo::One(5));
+    mem::discriminant(&Foo::Two(5));
+    mem::discriminant(ro);
+    mem::discriminant(*rro);
+    mem::discriminant(****rrrrro);
+}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.rs b/src/tools/clippy/tests/ui/mem_discriminant.rs
new file mode 100644
index 00000000000..55db50fcdc7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_discriminant.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#![deny(clippy::mem_discriminant_non_enum)]
+
+use std::mem;
+
+enum Foo {
+    One(usize),
+    Two(u8),
+}
+
+fn main() {
+    // bad
+    mem::discriminant(&&Some(2));
+    mem::discriminant(&&None::<u8>);
+    mem::discriminant(&&Foo::One(5));
+    mem::discriminant(&&Foo::Two(5));
+
+    let ro = &Some(3);
+    let rro = &ro;
+    mem::discriminant(&ro);
+    mem::discriminant(rro);
+    mem::discriminant(&rro);
+
+    macro_rules! mem_discriminant_but_in_a_macro {
+        ($param:expr) => {
+            mem::discriminant($param)
+        };
+    }
+
+    mem_discriminant_but_in_a_macro!(&rro);
+
+    let rrrrro = &&&rro;
+    mem::discriminant(&rrrrro);
+    mem::discriminant(*rrrrro);
+
+    // ok
+    mem::discriminant(&Some(2));
+    mem::discriminant(&None::<u8>);
+    mem::discriminant(&Foo::One(5));
+    mem::discriminant(&Foo::Two(5));
+    mem::discriminant(ro);
+    mem::discriminant(*rro);
+    mem::discriminant(****rrrrro);
+}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant.stderr b/src/tools/clippy/tests/ui/mem_discriminant.stderr
new file mode 100644
index 00000000000..8d9810970ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_discriminant.stderr
@@ -0,0 +1,94 @@
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:14:5
+   |
+LL |     mem::discriminant(&&Some(2));
+   |     ^^^^^^^^^^^^^^^^^^---------^
+   |                       |
+   |                       help: try dereferencing: `&Some(2)`
+   |
+note: the lint level is defined here
+  --> $DIR/mem_discriminant.rs:3:9
+   |
+LL | #![deny(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<u8>`
+  --> $DIR/mem_discriminant.rs:15:5
+   |
+LL |     mem::discriminant(&&None::<u8>);
+   |     ^^^^^^^^^^^^^^^^^^------------^
+   |                       |
+   |                       help: try dereferencing: `&None::<u8>`
+
+error: calling `mem::discriminant` on non-enum type `&Foo`
+  --> $DIR/mem_discriminant.rs:16:5
+   |
+LL |     mem::discriminant(&&Foo::One(5));
+   |     ^^^^^^^^^^^^^^^^^^-------------^
+   |                       |
+   |                       help: try dereferencing: `&Foo::One(5)`
+
+error: calling `mem::discriminant` on non-enum type `&Foo`
+  --> $DIR/mem_discriminant.rs:17:5
+   |
+LL |     mem::discriminant(&&Foo::Two(5));
+   |     ^^^^^^^^^^^^^^^^^^-------------^
+   |                       |
+   |                       help: try dereferencing: `&Foo::Two(5)`
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:21:5
+   |
+LL |     mem::discriminant(&ro);
+   |     ^^^^^^^^^^^^^^^^^^---^
+   |                       |
+   |                       help: try dereferencing: `ro`
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:22:5
+   |
+LL |     mem::discriminant(rro);
+   |     ^^^^^^^^^^^^^^^^^^---^
+   |                       |
+   |                       help: try dereferencing: `*rro`
+
+error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:23:5
+   |
+LL |     mem::discriminant(&rro);
+   |     ^^^^^^^^^^^^^^^^^^----^
+   |                       |
+   |                       help: try dereferencing: `*rro`
+
+error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:27:13
+   |
+LL |             mem::discriminant($param)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     mem_discriminant_but_in_a_macro!(&rro);
+   |     ---------------------------------------
+   |     |                                |
+   |     |                                help: try dereferencing: `*rro`
+   |     in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:34:5
+   |
+LL |     mem::discriminant(&rrrrro);
+   |     ^^^^^^^^^^^^^^^^^^-------^
+   |                       |
+   |                       help: try dereferencing: `****rrrrro`
+
+error: calling `mem::discriminant` on non-enum type `&&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:35:5
+   |
+LL |     mem::discriminant(*rrrrro);
+   |     ^^^^^^^^^^^^^^^^^^-------^
+   |                       |
+   |                       help: try dereferencing: `****rrrrro`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs
new file mode 100644
index 00000000000..e245d3257d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.rs
@@ -0,0 +1,16 @@
+#![deny(clippy::mem_discriminant_non_enum)]
+
+use std::mem;
+
+enum Foo {
+    One(usize),
+    Two(u8),
+}
+
+struct A(Foo);
+
+fn main() {
+    // bad
+    mem::discriminant(&"hello");
+    mem::discriminant(&A(Foo::One(0)));
+}
diff --git a/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr
new file mode 100644
index 00000000000..e2de3776f2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_discriminant_unfixable.stderr
@@ -0,0 +1,20 @@
+error: calling `mem::discriminant` on non-enum type `&str`
+  --> $DIR/mem_discriminant_unfixable.rs:14:5
+   |
+LL |     mem::discriminant(&"hello");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/mem_discriminant_unfixable.rs:1:9
+   |
+LL | #![deny(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `mem::discriminant` on non-enum type `A`
+  --> $DIR/mem_discriminant_unfixable.rs:15:5
+   |
+LL |     mem::discriminant(&A(Foo::One(0)));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mem_forget.rs b/src/tools/clippy/tests/ui/mem_forget.rs
new file mode 100644
index 00000000000..e5b35c098a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_forget.rs
@@ -0,0 +1,23 @@
+use std::rc::Rc;
+use std::sync::Arc;
+
+use std::mem as memstuff;
+use std::mem::forget as forgetSomething;
+
+#[warn(clippy::mem_forget)]
+#[allow(clippy::forget_copy)]
+fn main() {
+    let five: i32 = 5;
+    forgetSomething(five);
+
+    let six: Arc<i32> = Arc::new(6);
+    memstuff::forget(six);
+
+    let seven: Rc<i32> = Rc::new(7);
+    std::mem::forget(seven);
+
+    let eight: Vec<i32> = vec![8];
+    forgetSomething(eight);
+
+    std::mem::forget(7);
+}
diff --git a/src/tools/clippy/tests/ui/mem_forget.stderr b/src/tools/clippy/tests/ui/mem_forget.stderr
new file mode 100644
index 00000000000..a90d8b1655d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_forget.stderr
@@ -0,0 +1,22 @@
+error: usage of `mem::forget` on `Drop` type
+  --> $DIR/mem_forget.rs:14:5
+   |
+LL |     memstuff::forget(six);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mem-forget` implied by `-D warnings`
+
+error: usage of `mem::forget` on `Drop` type
+  --> $DIR/mem_forget.rs:17:5
+   |
+LL |     std::mem::forget(seven);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: usage of `mem::forget` on `Drop` type
+  --> $DIR/mem_forget.rs:20:5
+   |
+LL |     forgetSomething(eight);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed
new file mode 100644
index 00000000000..54e962e7116
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_replace.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(
+    clippy::all,
+    clippy::style,
+    clippy::mem_replace_option_with_none,
+    clippy::mem_replace_with_default
+)]
+
+use std::mem;
+
+fn replace_option_with_none() {
+    let mut an_option = Some(1);
+    let _ = an_option.take();
+    let an_option = &mut Some(1);
+    let _ = an_option.take();
+}
+
+fn replace_with_default() {
+    let mut s = String::from("foo");
+    let _ = std::mem::take(&mut s);
+    let s = &mut String::from("foo");
+    let _ = std::mem::take(s);
+    let _ = std::mem::take(s);
+}
+
+fn main() {
+    replace_option_with_none();
+    replace_with_default();
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs
new file mode 100644
index 00000000000..60f52781071
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_replace.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(
+    clippy::all,
+    clippy::style,
+    clippy::mem_replace_option_with_none,
+    clippy::mem_replace_with_default
+)]
+
+use std::mem;
+
+fn replace_option_with_none() {
+    let mut an_option = Some(1);
+    let _ = mem::replace(&mut an_option, None);
+    let an_option = &mut Some(1);
+    let _ = mem::replace(an_option, None);
+}
+
+fn replace_with_default() {
+    let mut s = String::from("foo");
+    let _ = std::mem::replace(&mut s, String::default());
+    let s = &mut String::from("foo");
+    let _ = std::mem::replace(s, String::default());
+    let _ = std::mem::replace(s, Default::default());
+}
+
+fn main() {
+    replace_option_with_none();
+    replace_with_default();
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr
new file mode 100644
index 00000000000..245d33aa4f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_replace.stderr
@@ -0,0 +1,36 @@
+error: replacing an `Option` with `None`
+  --> $DIR/mem_replace.rs:14:13
+   |
+LL |     let _ = mem::replace(&mut an_option, None);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
+   |
+   = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
+
+error: replacing an `Option` with `None`
+  --> $DIR/mem_replace.rs:16:13
+   |
+LL |     let _ = mem::replace(an_option, None);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
+
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> $DIR/mem_replace.rs:21:13
+   |
+LL |     let _ = std::mem::replace(&mut s, String::default());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
+   |
+   = note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
+
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> $DIR/mem_replace.rs:23:13
+   |
+LL |     let _ = std::mem::replace(s, String::default());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
+
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> $DIR/mem_replace.rs:24:13
+   |
+LL |     let _ = std::mem::replace(s, Default::default());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.rs b/src/tools/clippy/tests/ui/mem_replace_macro.rs
new file mode 100644
index 00000000000..0c09344b80d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_replace_macro.rs
@@ -0,0 +1,21 @@
+// aux-build:macro_rules.rs
+#![warn(clippy::mem_replace_with_default)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! take {
+    ($s:expr) => {
+        std::mem::replace($s, Default::default())
+    };
+}
+
+fn replace_with_default() {
+    let s = &mut String::from("foo");
+    take!(s);
+    take_external!(s);
+}
+
+fn main() {
+    replace_with_default();
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.stderr b/src/tools/clippy/tests/ui/mem_replace_macro.stderr
new file mode 100644
index 00000000000..4971a91050b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mem_replace_macro.stderr
@@ -0,0 +1,14 @@
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> $DIR/mem_replace_macro.rs:9:9
+   |
+LL |         std::mem::replace($s, Default::default())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     take!(s);
+   |     --------- in this macro invocation
+   |
+   = note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
new file mode 100644
index 00000000000..7880cf36415
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -0,0 +1,247 @@
+// aux-build:option_helpers.rs
+// edition:2018
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::default_trait_access,
+    clippy::missing_docs_in_private_items,
+    clippy::missing_safety_doc,
+    clippy::non_ascii_literal,
+    clippy::new_without_default,
+    clippy::needless_pass_by_value,
+    clippy::print_stdout,
+    clippy::must_use_candidate,
+    clippy::use_self,
+    clippy::useless_format,
+    clippy::wrong_self_convention,
+    clippy::unused_self,
+    unused
+)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::HashSet;
+use std::collections::VecDeque;
+use std::iter::FromIterator;
+use std::ops::Mul;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+use option_helpers::IteratorFalsePositives;
+
+pub struct T;
+
+impl T {
+    pub fn add(self, other: T) -> T {
+        self
+    }
+
+    // no error, not public interface
+    pub(crate) fn drop(&mut self) {}
+
+    // no error, private function
+    fn neg(self) -> Self {
+        self
+    }
+
+    // no error, private function
+    fn eq(&self, other: T) -> bool {
+        true
+    }
+
+    // No error; self is a ref.
+    fn sub(&self, other: T) -> &T {
+        self
+    }
+
+    // No error; different number of arguments.
+    fn div(self) -> T {
+        self
+    }
+
+    // No error; wrong return type.
+    fn rem(self, other: T) {}
+
+    // Fine
+    fn into_u32(self) -> u32 {
+        0
+    }
+
+    fn into_u16(&self) -> u16 {
+        0
+    }
+
+    fn to_something(self) -> u32 {
+        0
+    }
+
+    fn new(self) -> Self {
+        unimplemented!();
+    }
+}
+
+pub struct T1;
+
+impl T1 {
+    // Shouldn't trigger lint as it is unsafe.
+    pub unsafe fn add(self, rhs: T1) -> T1 {
+        self
+    }
+
+    // Should not trigger lint since this is an async function.
+    pub async fn next(&mut self) -> Option<T1> {
+        None
+    }
+}
+
+struct Lt<'a> {
+    foo: &'a u32,
+}
+
+impl<'a> Lt<'a> {
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    #[allow(clippy::needless_lifetimes)]
+    pub fn new<'b>(s: &'b str) -> Lt<'b> {
+        unimplemented!()
+    }
+}
+
+struct Lt2<'a> {
+    foo: &'a u32,
+}
+
+impl<'a> Lt2<'a> {
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    pub fn new(s: &str) -> Lt2 {
+        unimplemented!()
+    }
+}
+
+struct Lt3<'a> {
+    foo: &'a u32,
+}
+
+impl<'a> Lt3<'a> {
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    pub fn new() -> Lt3<'static> {
+        unimplemented!()
+    }
+}
+
+#[derive(Clone, Copy)]
+struct U;
+
+impl U {
+    fn new() -> Self {
+        U
+    }
+    // Ok because `U` is `Copy`.
+    fn to_something(self) -> u32 {
+        0
+    }
+}
+
+struct V<T> {
+    _dummy: T,
+}
+
+impl<T> V<T> {
+    fn new() -> Option<V<T>> {
+        None
+    }
+}
+
+struct AsyncNew;
+
+impl AsyncNew {
+    async fn new() -> Option<Self> {
+        None
+    }
+}
+
+struct BadNew;
+
+impl BadNew {
+    fn new() -> i32 {
+        0
+    }
+}
+
+impl Mul<T> for T {
+    type Output = T;
+    // No error, obviously.
+    fn mul(self, other: T) -> T {
+        self
+    }
+}
+
+/// Checks implementation of `FILTER_NEXT` lint.
+#[rustfmt::skip]
+fn filter_next() {
+    let v = vec![3, 2, 1, 0, -1, -2, -3];
+
+    // Single-line case.
+    let _ = v.iter().filter(|&x| *x < 0).next();
+
+    // Multi-line case.
+    let _ = v.iter().filter(|&x| {
+                                *x < 0
+                            }
+                   ).next();
+
+    // Check that hat we don't lint if the caller is not an `Iterator`.
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.filter().next();
+}
+
+/// Checks implementation of `SEARCH_IS_SOME` lint.
+#[rustfmt::skip]
+fn search_is_some() {
+    let v = vec![3, 2, 1, 0, -1, -2, -3];
+    let y = &&42;
+
+    // Check `find().is_some()`, single-line case.
+    let _ = v.iter().find(|&x| *x < 0).is_some();
+    let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+    let _ = (0..1).find(|x| *x == 0).is_some();
+    let _ = v.iter().find(|x| **x == 0).is_some();
+
+    // Check `find().is_some()`, multi-line case.
+    let _ = v.iter().find(|&x| {
+                              *x < 0
+                          }
+                   ).is_some();
+
+    // Check `position().is_some()`, single-line case.
+    let _ = v.iter().position(|&x| x < 0).is_some();
+
+    // Check `position().is_some()`, multi-line case.
+    let _ = v.iter().position(|&x| {
+                                  x < 0
+                              }
+                   ).is_some();
+
+    // Check `rposition().is_some()`, single-line case.
+    let _ = v.iter().rposition(|&x| x < 0).is_some();
+
+    // Check `rposition().is_some()`, multi-line case.
+    let _ = v.iter().rposition(|&x| {
+                                   x < 0
+                               }
+                   ).is_some();
+
+    // Check that we don't lint if the caller is not an `Iterator`.
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.find().is_some();
+    let _ = foo.position().is_some();
+    let _ = foo.rposition().is_some();
+}
+
+fn main() {
+    filter_next();
+    search_is_some();
+}
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
new file mode 100644
index 00000000000..01cf487ac14
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -0,0 +1,109 @@
+error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
+  --> $DIR/methods.rs:39:5
+   |
+LL | /     pub fn add(self, other: T) -> T {
+LL | |         self
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
+
+error: methods called `new` usually return `Self`
+  --> $DIR/methods.rs:169:5
+   |
+LL | /     fn new() -> i32 {
+LL | |         0
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
+
+error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
+  --> $DIR/methods.rs:188:13
+   |
+LL |     let _ = v.iter().filter(|&x| *x < 0).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filter-next` implied by `-D warnings`
+   = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
+
+error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
+  --> $DIR/methods.rs:191:13
+   |
+LL |       let _ = v.iter().filter(|&x| {
+   |  _____________^
+LL | |                                 *x < 0
+LL | |                             }
+LL | |                    ).next();
+   | |___________________________^
+
+error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:208:22
+   |
+LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
+   |
+   = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:209:20
+   |
+LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
+
+error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:210:20
+   |
+LL |     let _ = (0..1).find(|x| *x == 0).is_some();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:211:22
+   |
+LL |     let _ = v.iter().find(|x| **x == 0).is_some();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:214:13
+   |
+LL |       let _ = v.iter().find(|&x| {
+   |  _____________^
+LL | |                               *x < 0
+LL | |                           }
+LL | |                    ).is_some();
+   | |______________________________^
+
+error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:220:22
+   |
+LL |     let _ = v.iter().position(|&x| x < 0).is_some();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
+
+error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:223:13
+   |
+LL |       let _ = v.iter().position(|&x| {
+   |  _____________^
+LL | |                                   x < 0
+LL | |                               }
+LL | |                    ).is_some();
+   | |______________________________^
+
+error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:229:22
+   |
+LL |     let _ = v.iter().rposition(|&x| x < 0).is_some();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
+
+error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
+  --> $DIR/methods.rs:232:13
+   |
+LL |       let _ = v.iter().rposition(|&x| {
+   |  _____________^
+LL | |                                    x < 0
+LL | |                                }
+LL | |                    ).is_some();
+   | |______________________________^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
new file mode 100644
index 00000000000..8307d4b3019
--- /dev/null
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -0,0 +1,33 @@
+#![warn(clippy::all)]
+
+use std::cmp::max as my_max;
+use std::cmp::min as my_min;
+use std::cmp::{max, min};
+
+const LARGE: usize = 3;
+
+fn main() {
+    let x;
+    x = 2usize;
+    min(1, max(3, x));
+    min(max(3, x), 1);
+    max(min(x, 1), 3);
+    max(3, min(x, 1));
+
+    my_max(3, my_min(x, 1));
+
+    min(3, max(1, x)); // ok, could be 1, 2 or 3 depending on x
+
+    min(1, max(LARGE, x)); // no error, we don't lookup consts here
+
+    let y = 2isize;
+    min(max(y, -1), 3);
+
+    let s;
+    s = "Hello";
+
+    min("Apple", max("Zoo", s));
+    max(min(s, "Apple"), "Zoo");
+
+    max("Apple", min(s, "Zoo")); // ok
+}
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
new file mode 100644
index 00000000000..b552c137f7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -0,0 +1,46 @@
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:12:5
+   |
+LL |     min(1, max(3, x));
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::min-max` implied by `-D warnings`
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:13:5
+   |
+LL |     min(max(3, x), 1);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:14:5
+   |
+LL |     max(min(x, 1), 3);
+   |     ^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:15:5
+   |
+LL |     max(3, min(x, 1));
+   |     ^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:17:5
+   |
+LL |     my_max(3, my_min(x, 1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:29:5
+   |
+LL |     min("Apple", max("Zoo", s));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this `min`/`max` combination leads to constant result
+  --> $DIR/min_max.rs:30:5
+   |
+LL |     max(min(s, "Apple"), "Zoo");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed
new file mode 100644
index 00000000000..3ee77dcac31
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+
+#![warn(clippy::mismatched_target_os)]
+#![allow(unused)]
+
+#[cfg(target_os = "cloudabi")]
+fn cloudabi() {}
+
+#[cfg(target_os = "hermit")]
+fn hermit() {}
+
+#[cfg(target_os = "wasi")]
+fn wasi() {}
+
+#[cfg(target_os = "none")]
+fn none() {}
+
+// list with conditions
+#[cfg(all(not(any(windows, target_os = "cloudabi")), target_os = "wasi"))]
+fn list() {}
+
+// windows is a valid target family, should be ignored
+#[cfg(windows)]
+fn windows() {}
+
+// correct use, should be ignored
+#[cfg(target_os = "hermit")]
+fn correct() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs
new file mode 100644
index 00000000000..9cc411418e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+
+#![warn(clippy::mismatched_target_os)]
+#![allow(unused)]
+
+#[cfg(cloudabi)]
+fn cloudabi() {}
+
+#[cfg(hermit)]
+fn hermit() {}
+
+#[cfg(wasi)]
+fn wasi() {}
+
+#[cfg(none)]
+fn none() {}
+
+// list with conditions
+#[cfg(all(not(any(windows, cloudabi)), wasi))]
+fn list() {}
+
+// windows is a valid target family, should be ignored
+#[cfg(windows)]
+fn windows() {}
+
+// correct use, should be ignored
+#[cfg(target_os = "hermit")]
+fn correct() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr
new file mode 100644
index 00000000000..78fc27752d2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr
@@ -0,0 +1,51 @@
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_non_unix.rs:6:1
+   |
+LL | #[cfg(cloudabi)]
+   | ^^^^^^--------^^
+   |       |
+   |       help: try: `target_os = "cloudabi"`
+   |
+   = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_non_unix.rs:9:1
+   |
+LL | #[cfg(hermit)]
+   | ^^^^^^------^^
+   |       |
+   |       help: try: `target_os = "hermit"`
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_non_unix.rs:12:1
+   |
+LL | #[cfg(wasi)]
+   | ^^^^^^----^^
+   |       |
+   |       help: try: `target_os = "wasi"`
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_non_unix.rs:15:1
+   |
+LL | #[cfg(none)]
+   | ^^^^^^----^^
+   |       |
+   |       help: try: `target_os = "none"`
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_non_unix.rs:19:1
+   |
+LL | #[cfg(all(not(any(windows, cloudabi)), wasi))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL | #[cfg(all(not(any(windows, target_os = "cloudabi")), wasi))]
+   |                            ^^^^^^^^^^^^^^^^^^^^^^
+help: try
+   |
+LL | #[cfg(all(not(any(windows, cloudabi)), target_os = "wasi"))]
+   |                                        ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed
new file mode 100644
index 00000000000..7d9d406d99d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed
@@ -0,0 +1,62 @@
+// run-rustfix
+
+#![warn(clippy::mismatched_target_os)]
+#![allow(unused)]
+
+#[cfg(target_os = "linux")]
+fn linux() {}
+
+#[cfg(target_os = "freebsd")]
+fn freebsd() {}
+
+#[cfg(target_os = "dragonfly")]
+fn dragonfly() {}
+
+#[cfg(target_os = "openbsd")]
+fn openbsd() {}
+
+#[cfg(target_os = "netbsd")]
+fn netbsd() {}
+
+#[cfg(target_os = "macos")]
+fn macos() {}
+
+#[cfg(target_os = "ios")]
+fn ios() {}
+
+#[cfg(target_os = "android")]
+fn android() {}
+
+#[cfg(target_os = "emscripten")]
+fn emscripten() {}
+
+#[cfg(target_os = "fuchsia")]
+fn fuchsia() {}
+
+#[cfg(target_os = "haiku")]
+fn haiku() {}
+
+#[cfg(target_os = "illumos")]
+fn illumos() {}
+
+#[cfg(target_os = "l4re")]
+fn l4re() {}
+
+#[cfg(target_os = "redox")]
+fn redox() {}
+
+#[cfg(target_os = "solaris")]
+fn solaris() {}
+
+#[cfg(target_os = "vxworks")]
+fn vxworks() {}
+
+// list with conditions
+#[cfg(all(not(any(target_os = "solaris", target_os = "linux")), target_os = "freebsd"))]
+fn list() {}
+
+// correct use, should be ignored
+#[cfg(target_os = "freebsd")]
+fn correct() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs
new file mode 100644
index 00000000000..c1177f1eedc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs
@@ -0,0 +1,62 @@
+// run-rustfix
+
+#![warn(clippy::mismatched_target_os)]
+#![allow(unused)]
+
+#[cfg(linux)]
+fn linux() {}
+
+#[cfg(freebsd)]
+fn freebsd() {}
+
+#[cfg(dragonfly)]
+fn dragonfly() {}
+
+#[cfg(openbsd)]
+fn openbsd() {}
+
+#[cfg(netbsd)]
+fn netbsd() {}
+
+#[cfg(macos)]
+fn macos() {}
+
+#[cfg(ios)]
+fn ios() {}
+
+#[cfg(android)]
+fn android() {}
+
+#[cfg(emscripten)]
+fn emscripten() {}
+
+#[cfg(fuchsia)]
+fn fuchsia() {}
+
+#[cfg(haiku)]
+fn haiku() {}
+
+#[cfg(illumos)]
+fn illumos() {}
+
+#[cfg(l4re)]
+fn l4re() {}
+
+#[cfg(redox)]
+fn redox() {}
+
+#[cfg(solaris)]
+fn solaris() {}
+
+#[cfg(vxworks)]
+fn vxworks() {}
+
+// list with conditions
+#[cfg(all(not(any(solaris, linux)), freebsd))]
+fn list() {}
+
+// correct use, should be ignored
+#[cfg(target_os = "freebsd")]
+fn correct() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr
new file mode 100644
index 00000000000..fe9aeedb59c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr
@@ -0,0 +1,183 @@
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:6:1
+   |
+LL | #[cfg(linux)]
+   | ^^^^^^-----^^
+   |       |
+   |       help: try: `target_os = "linux"`
+   |
+   = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:9:1
+   |
+LL | #[cfg(freebsd)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "freebsd"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:12:1
+   |
+LL | #[cfg(dragonfly)]
+   | ^^^^^^---------^^
+   |       |
+   |       help: try: `target_os = "dragonfly"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:15:1
+   |
+LL | #[cfg(openbsd)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "openbsd"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:18:1
+   |
+LL | #[cfg(netbsd)]
+   | ^^^^^^------^^
+   |       |
+   |       help: try: `target_os = "netbsd"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:21:1
+   |
+LL | #[cfg(macos)]
+   | ^^^^^^-----^^
+   |       |
+   |       help: try: `target_os = "macos"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:24:1
+   |
+LL | #[cfg(ios)]
+   | ^^^^^^---^^
+   |       |
+   |       help: try: `target_os = "ios"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:27:1
+   |
+LL | #[cfg(android)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "android"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:30:1
+   |
+LL | #[cfg(emscripten)]
+   | ^^^^^^----------^^
+   |       |
+   |       help: try: `target_os = "emscripten"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:33:1
+   |
+LL | #[cfg(fuchsia)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "fuchsia"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:36:1
+   |
+LL | #[cfg(haiku)]
+   | ^^^^^^-----^^
+   |       |
+   |       help: try: `target_os = "haiku"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:39:1
+   |
+LL | #[cfg(illumos)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "illumos"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:42:1
+   |
+LL | #[cfg(l4re)]
+   | ^^^^^^----^^
+   |       |
+   |       help: try: `target_os = "l4re"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:45:1
+   |
+LL | #[cfg(redox)]
+   | ^^^^^^-----^^
+   |       |
+   |       help: try: `target_os = "redox"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:48:1
+   |
+LL | #[cfg(solaris)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "solaris"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:51:1
+   |
+LL | #[cfg(vxworks)]
+   | ^^^^^^-------^^
+   |       |
+   |       help: try: `target_os = "vxworks"`
+   |
+   = help: Did you mean `unix`?
+
+error: operating system used in target family position
+  --> $DIR/mismatched_target_os_unix.rs:55:1
+   |
+LL | #[cfg(all(not(any(solaris, linux)), freebsd))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: Did you mean `unix`?
+help: try
+   |
+LL | #[cfg(all(not(any(target_os = "solaris", linux)), freebsd))]
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+help: try
+   |
+LL | #[cfg(all(not(any(solaris, target_os = "linux")), freebsd))]
+   |                            ^^^^^^^^^^^^^^^^^^^
+help: try
+   |
+LL | #[cfg(all(not(any(solaris, linux)), target_os = "freebsd"))]
+   |                                     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs b/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs
new file mode 100644
index 00000000000..51fd57df8df
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs
@@ -0,0 +1,3 @@
+#![warn(clippy::missing_docs_in_private_items)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr b/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr
new file mode 100644
index 00000000000..da46f988636
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr
@@ -0,0 +1,12 @@
+error: missing documentation for crate
+  --> $DIR/missing-doc-crate-missing.rs:1:1
+   |
+LL | / #![warn(clippy::missing_docs_in_private_items)]
+LL | |
+LL | | fn main() {}
+   | |____________^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing-doc-crate.rs
new file mode 100644
index 00000000000..04711f86488
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-crate.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::missing_docs_in_private_items)]
+#![feature(external_doc)]
+#![doc(include = "../../README.md")]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.stderr b/src/tools/clippy/tests/ui/missing-doc-crate.stderr
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-crate.stderr
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs
new file mode 100644
index 00000000000..57af84dcdf4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.rs
@@ -0,0 +1,87 @@
+#![warn(clippy::missing_docs_in_private_items)]
+#![allow(dead_code)]
+#![feature(associated_type_defaults)]
+
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+struct Foo {
+    a: isize,
+    b: isize,
+}
+
+pub struct PubFoo {
+    pub a: isize,
+    b: isize,
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub struct PubFoo2 {
+    pub a: isize,
+    pub c: isize,
+}
+
+/// dox
+pub trait A {
+    /// dox
+    fn foo(&self);
+    /// dox
+    fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait B {
+    fn foo(&self);
+    fn foo_with_impl(&self) {}
+}
+
+pub trait C {
+    fn foo(&self);
+    fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub trait D {
+    fn dummy(&self) {}
+}
+
+/// dox
+pub trait E: Sized {
+    type AssociatedType;
+    type AssociatedTypeDef = Self;
+
+    /// dox
+    type DocumentedType;
+    /// dox
+    type DocumentedTypeDef = Self;
+    /// dox
+    fn dummy(&self) {}
+}
+
+impl Foo {
+    pub fn foo() {}
+    fn bar() {}
+}
+
+impl PubFoo {
+    pub fn foo() {}
+    /// dox
+    pub fn foo1() {}
+    fn foo2() {}
+    #[allow(clippy::missing_docs_in_private_items)]
+    pub fn foo3() {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait F {
+    fn a();
+    fn b(&self);
+}
+
+// should need to redefine documentation for implementations of traits
+impl F for Foo {
+    fn a() {}
+    fn b(&self) {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
new file mode 100644
index 00000000000..9656a39abce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
@@ -0,0 +1,103 @@
+error: missing documentation for a struct
+  --> $DIR/missing-doc-impl.rs:8:1
+   |
+LL | / struct Foo {
+LL | |     a: isize,
+LL | |     b: isize,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc-impl.rs:9:5
+   |
+LL |     a: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc-impl.rs:10:5
+   |
+LL |     b: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a struct
+  --> $DIR/missing-doc-impl.rs:13:1
+   |
+LL | / pub struct PubFoo {
+LL | |     pub a: isize,
+LL | |     b: isize,
+LL | | }
+   | |_^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc-impl.rs:14:5
+   |
+LL |     pub a: isize,
+   |     ^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc-impl.rs:15:5
+   |
+LL |     b: isize,
+   |     ^^^^^^^^
+
+error: missing documentation for a trait
+  --> $DIR/missing-doc-impl.rs:38:1
+   |
+LL | / pub trait C {
+LL | |     fn foo(&self);
+LL | |     fn foo_with_impl(&self) {}
+LL | | }
+   | |_^
+
+error: missing documentation for a trait method
+  --> $DIR/missing-doc-impl.rs:39:5
+   |
+LL |     fn foo(&self);
+   |     ^^^^^^^^^^^^^^
+
+error: missing documentation for a trait method
+  --> $DIR/missing-doc-impl.rs:40:5
+   |
+LL |     fn foo_with_impl(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+  --> $DIR/missing-doc-impl.rs:50:5
+   |
+LL |     type AssociatedType;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+  --> $DIR/missing-doc-impl.rs:51:5
+   |
+LL |     type AssociatedTypeDef = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a method
+  --> $DIR/missing-doc-impl.rs:62:5
+   |
+LL |     pub fn foo() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: missing documentation for a method
+  --> $DIR/missing-doc-impl.rs:63:5
+   |
+LL |     fn bar() {}
+   |     ^^^^^^^^^^^
+
+error: missing documentation for a method
+  --> $DIR/missing-doc-impl.rs:67:5
+   |
+LL |     pub fn foo() {}
+   |     ^^^^^^^^^^^^^^^
+
+error: missing documentation for a method
+  --> $DIR/missing-doc-impl.rs:70:5
+   |
+LL |     fn foo2() {}
+   |     ^^^^^^^^^^^^
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing-doc.rs
new file mode 100644
index 00000000000..a9bf7140a1e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc.rs
@@ -0,0 +1,102 @@
+#![warn(clippy::missing_docs_in_private_items)]
+// When denying at the crate level, be sure to not get random warnings from the
+// injected intrinsics by the compiler.
+#![allow(dead_code)]
+#![feature(global_asm)]
+
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+type Typedef = String;
+pub type PubTypedef = String;
+
+mod module_no_dox {}
+pub mod pub_module_no_dox {}
+
+/// dox
+pub fn foo() {}
+pub fn foo2() {}
+fn foo3() {}
+#[allow(clippy::missing_docs_in_private_items)]
+pub fn foo4() {}
+
+// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
+// applies recursively
+#[doc(hidden)]
+mod a {
+    pub fn baz() {}
+    pub mod b {
+        pub fn baz() {}
+    }
+}
+
+enum Baz {
+    BazA { a: isize, b: isize },
+    BarB,
+}
+
+pub enum PubBaz {
+    PubBazA { a: isize },
+}
+
+/// dox
+pub enum PubBaz2 {
+    /// dox
+    PubBaz2A {
+        /// dox
+        a: isize,
+    },
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub enum PubBaz3 {
+    PubBaz3A { b: isize },
+}
+
+#[doc(hidden)]
+pub fn baz() {}
+
+const FOO: u32 = 0;
+/// dox
+pub const FOO1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub const FOO2: u32 = 0;
+#[doc(hidden)]
+pub const FOO3: u32 = 0;
+pub const FOO4: u32 = 0;
+
+static BAR: u32 = 0;
+/// dox
+pub static BAR1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub static BAR2: u32 = 0;
+#[doc(hidden)]
+pub static BAR3: u32 = 0;
+pub static BAR4: u32 = 0;
+
+mod internal_impl {
+    /// dox
+    pub fn documented() {}
+    pub fn undocumented1() {}
+    pub fn undocumented2() {}
+    fn undocumented3() {}
+    /// dox
+    pub mod globbed {
+        /// dox
+        pub fn also_documented() {}
+        pub fn also_undocumented1() {}
+        fn also_undocumented2() {}
+    }
+}
+/// dox
+pub mod public_interface {
+    pub use internal_impl::documented as foo;
+    pub use internal_impl::globbed::*;
+    pub use internal_impl::undocumented1 as bar;
+    pub use internal_impl::{documented, undocumented2};
+}
+
+fn main() {}
+
+// Ensure global asm doesn't require documentation.
+global_asm! { "" }
diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing-doc.stderr
new file mode 100644
index 00000000000..a876dc078eb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing-doc.stderr
@@ -0,0 +1,159 @@
+error: missing documentation for a type alias
+  --> $DIR/missing-doc.rs:10:1
+   |
+LL | type Typedef = String;
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a type alias
+  --> $DIR/missing-doc.rs:11:1
+   |
+LL | pub type PubTypedef = String;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing-doc.rs:13:1
+   |
+LL | mod module_no_dox {}
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing-doc.rs:14:1
+   |
+LL | pub mod pub_module_no_dox {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:18:1
+   |
+LL | pub fn foo2() {}
+   | ^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:19:1
+   |
+LL | fn foo3() {}
+   | ^^^^^^^^^^^^
+
+error: missing documentation for an enum
+  --> $DIR/missing-doc.rs:33:1
+   |
+LL | / enum Baz {
+LL | |     BazA { a: isize, b: isize },
+LL | |     BarB,
+LL | | }
+   | |_^
+
+error: missing documentation for a variant
+  --> $DIR/missing-doc.rs:34:5
+   |
+LL |     BazA { a: isize, b: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc.rs:34:12
+   |
+LL |     BazA { a: isize, b: isize },
+   |            ^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc.rs:34:22
+   |
+LL |     BazA { a: isize, b: isize },
+   |                      ^^^^^^^^
+
+error: missing documentation for a variant
+  --> $DIR/missing-doc.rs:35:5
+   |
+LL |     BarB,
+   |     ^^^^
+
+error: missing documentation for an enum
+  --> $DIR/missing-doc.rs:38:1
+   |
+LL | / pub enum PubBaz {
+LL | |     PubBazA { a: isize },
+LL | | }
+   | |_^
+
+error: missing documentation for a variant
+  --> $DIR/missing-doc.rs:39:5
+   |
+LL |     PubBazA { a: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/missing-doc.rs:39:15
+   |
+LL |     PubBazA { a: isize },
+   |               ^^^^^^^^
+
+error: missing documentation for a constant
+  --> $DIR/missing-doc.rs:59:1
+   |
+LL | const FOO: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a constant
+  --> $DIR/missing-doc.rs:66:1
+   |
+LL | pub const FOO4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+  --> $DIR/missing-doc.rs:68:1
+   |
+LL | static BAR: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+  --> $DIR/missing-doc.rs:75:1
+   |
+LL | pub static BAR4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+  --> $DIR/missing-doc.rs:77:1
+   |
+LL | / mod internal_impl {
+LL | |     /// dox
+LL | |     pub fn documented() {}
+LL | |     pub fn undocumented1() {}
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:80:5
+   |
+LL |     pub fn undocumented1() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:81:5
+   |
+LL |     pub fn undocumented2() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:82:5
+   |
+LL |     fn undocumented3() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:87:9
+   |
+LL |         pub fn also_undocumented1() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/missing-doc.rs:88:9
+   |
+LL |         fn also_undocumented2() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
new file mode 100644
index 00000000000..ba352ef9ee9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -0,0 +1,103 @@
+//! False-positive tests to ensure we don't suggest `const` for things where it would cause a
+//! compilation error.
+//! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
+
+#![warn(clippy::missing_const_for_fn)]
+#![allow(incomplete_features)]
+#![feature(start, const_generics)]
+
+struct Game;
+
+// This should not be linted because it's already const
+const fn already_const() -> i32 {
+    32
+}
+
+impl Game {
+    // This should not be linted because it's already const
+    pub const fn already_const() -> i32 {
+        32
+    }
+}
+
+// Allowing on this function, because it would lint, which we don't want in this case.
+#[allow(clippy::missing_const_for_fn)]
+fn random() -> u32 {
+    42
+}
+
+// We should not suggest to make this function `const` because `random()` is non-const
+fn random_caller() -> u32 {
+    random()
+}
+
+static Y: u32 = 0;
+
+// We should not suggest to make this function `const` because const functions are not allowed to
+// refer to a static variable
+fn get_y() -> u32 {
+    Y
+    //~^ ERROR E0013
+}
+
+// Don't lint entrypoint functions
+#[start]
+fn init(num: isize, something: *const *const u8) -> isize {
+    1
+}
+
+trait Foo {
+    // This should not be suggested to be made const
+    // (rustc doesn't allow const trait methods)
+    fn f() -> u32;
+
+    // This should not be suggested to be made const either
+    fn g() -> u32 {
+        33
+    }
+}
+
+// Don't lint in external macros (derive)
+#[derive(PartialEq, Eq)]
+struct Point(isize, isize);
+
+impl std::ops::Add for Point {
+    type Output = Self;
+
+    // Don't lint in trait impls of derived methods
+    fn add(self, other: Self) -> Self {
+        Point(self.0 + other.0, self.1 + other.1)
+    }
+}
+
+mod with_drop {
+    pub struct A;
+    pub struct B;
+    impl Drop for A {
+        fn drop(&mut self) {}
+    }
+
+    impl A {
+        // This can not be const because the type implements `Drop`.
+        pub fn a(self) -> B {
+            B
+        }
+    }
+
+    impl B {
+        // This can not be const because `a` implements `Drop`.
+        pub fn a(self, a: A) -> B {
+            B
+        }
+    }
+}
+
+fn const_generic_params<T, const N: usize>(t: &[T; N]) -> &[T; N] {
+    t
+}
+
+fn const_generic_return<T, const N: usize>(t: &[T]) -> &[T; N] {
+    let p = t.as_ptr() as *const [T; N];
+
+    unsafe { &*p }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.stderr
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.stderr
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
new file mode 100644
index 00000000000..c6f44b7daa3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -0,0 +1,74 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(incomplete_features, clippy::let_and_return)]
+#![feature(const_generics)]
+
+use std::mem::transmute;
+
+struct Game {
+    guess: i32,
+}
+
+impl Game {
+    // Could be const
+    pub fn new() -> Self {
+        Self { guess: 42 }
+    }
+
+    fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
+        b
+    }
+}
+
+// Could be const
+fn one() -> i32 {
+    1
+}
+
+// Could also be const
+fn two() -> i32 {
+    let abc = 2;
+    abc
+}
+
+// Could be const (since Rust 1.39)
+fn string() -> String {
+    String::new()
+}
+
+// Could be const
+unsafe fn four() -> i32 {
+    4
+}
+
+// Could also be const
+fn generic<T>(t: T) -> T {
+    t
+}
+
+fn sub(x: u32) -> usize {
+    unsafe { transmute(&x) }
+}
+
+// NOTE: This is currently not yet allowed to be const
+// Once implemented, Clippy should be able to suggest this as const, too.
+fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+    t[0]
+}
+
+mod with_drop {
+    pub struct A;
+    pub struct B;
+    impl Drop for A {
+        fn drop(&mut self) {}
+    }
+
+    impl B {
+        // This can be const, because `a` is passed by reference
+        pub fn b(self, a: &A) -> B {
+            B
+        }
+    }
+}
+
+// Should not be const
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
new file mode 100644
index 00000000000..8dde56cd79f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -0,0 +1,77 @@
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:13:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |         Self { guess: 42 }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:17:5
+   |
+LL | /     fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
+LL | |         b
+LL | |     }
+   | |_____^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:23:1
+   |
+LL | / fn one() -> i32 {
+LL | |     1
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:28:1
+   |
+LL | / fn two() -> i32 {
+LL | |     let abc = 2;
+LL | |     abc
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:34:1
+   |
+LL | / fn string() -> String {
+LL | |     String::new()
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:39:1
+   |
+LL | / unsafe fn four() -> i32 {
+LL | |     4
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:44:1
+   |
+LL | / fn generic<T>(t: T) -> T {
+LL | |     t
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:48:1
+   |
+LL | / fn sub(x: u32) -> usize {
+LL | |     unsafe { transmute(&x) }
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:67:9
+   |
+LL | /         pub fn b(self, a: &A) -> B {
+LL | |             B
+LL | |         }
+   | |_________^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs
new file mode 100644
index 00000000000..b73b24b8e0a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_inline.rs
@@ -0,0 +1,66 @@
+#![warn(clippy::missing_inline_in_public_items)]
+#![crate_type = "dylib"]
+// When denying at the crate level, be sure to not get random warnings from the
+// injected intrinsics by the compiler.
+#![allow(dead_code, non_snake_case)]
+
+type Typedef = String;
+pub type PubTypedef = String;
+
+struct Foo {} // ok
+pub struct PubFoo {} // ok
+enum FooE {} // ok
+pub enum PubFooE {} // ok
+
+mod module {} // ok
+pub mod pub_module {} // ok
+
+fn foo() {}
+pub fn pub_foo() {} // missing #[inline]
+#[inline]
+pub fn pub_foo_inline() {} // ok
+#[inline(always)]
+pub fn pub_foo_inline_always() {} // ok
+
+#[allow(clippy::missing_inline_in_public_items)]
+pub fn pub_foo_no_inline() {}
+
+trait Bar {
+    fn Bar_a(); // ok
+    fn Bar_b() {} // ok
+}
+
+pub trait PubBar {
+    fn PubBar_a(); // ok
+    fn PubBar_b() {} // missing #[inline]
+    #[inline]
+    fn PubBar_c() {} // ok
+}
+
+// none of these need inline because Foo is not exported
+impl PubBar for Foo {
+    fn PubBar_a() {} // ok
+    fn PubBar_b() {} // ok
+    fn PubBar_c() {} // ok
+}
+
+// all of these need inline because PubFoo is exported
+impl PubBar for PubFoo {
+    fn PubBar_a() {} // missing #[inline]
+    fn PubBar_b() {} // missing #[inline]
+    fn PubBar_c() {} // missing #[inline]
+}
+
+// do not need inline because Foo is not exported
+impl Foo {
+    fn FooImpl() {} // ok
+}
+
+// need inline because PubFoo is exported
+impl PubFoo {
+    pub fn PubFooImpl() {} // missing #[inline]
+}
+
+// do not lint this since users cannot control the external code
+#[derive(Debug)]
+pub struct S {}
diff --git a/src/tools/clippy/tests/ui/missing_inline.stderr b/src/tools/clippy/tests/ui/missing_inline.stderr
new file mode 100644
index 00000000000..40b92b7647b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_inline.stderr
@@ -0,0 +1,40 @@
+error: missing `#[inline]` for a function
+  --> $DIR/missing_inline.rs:19:1
+   |
+LL | pub fn pub_foo() {} // missing #[inline]
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings`
+
+error: missing `#[inline]` for a default trait method
+  --> $DIR/missing_inline.rs:35:5
+   |
+LL |     fn PubBar_b() {} // missing #[inline]
+   |     ^^^^^^^^^^^^^^^^
+
+error: missing `#[inline]` for a method
+  --> $DIR/missing_inline.rs:49:5
+   |
+LL |     fn PubBar_a() {} // missing #[inline]
+   |     ^^^^^^^^^^^^^^^^
+
+error: missing `#[inline]` for a method
+  --> $DIR/missing_inline.rs:50:5
+   |
+LL |     fn PubBar_b() {} // missing #[inline]
+   |     ^^^^^^^^^^^^^^^^
+
+error: missing `#[inline]` for a method
+  --> $DIR/missing_inline.rs:51:5
+   |
+LL |     fn PubBar_c() {} // missing #[inline]
+   |     ^^^^^^^^^^^^^^^^
+
+error: missing `#[inline]` for a method
+  --> $DIR/missing_inline.rs:61:5
+   |
+LL |     pub fn PubFooImpl() {} // missing #[inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
new file mode 100644
index 00000000000..baee7735730
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+
+fn main() {
+    let fail14 = 2_i32;
+    let fail15 = 4_i64;
+    let fail16 = 7_i8; //
+    let fail17 = 23_i16; //
+    let ok18 = 23_128;
+
+    let fail20 = 2_i8; //
+    let fail21 = 4_i16; //
+
+    let fail24 = 12.34_f64;
+    let fail25 = 1E2_f32;
+    let fail26 = 43E7_f64;
+    let fail27 = 243E17_f32;
+    #[allow(overflowing_literals)]
+    let fail28 = 241_251_235E723_f64;
+    let fail29 = 42_279.911_f32;
+
+    let _ = 1.123_45E1_f32;
+}
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
new file mode 100644
index 00000000000..6de447f4021
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+
+fn main() {
+    let fail14 = 2_32;
+    let fail15 = 4_64;
+    let fail16 = 7_8; //
+    let fail17 = 23_16; //
+    let ok18 = 23_128;
+
+    let fail20 = 2__8; //
+    let fail21 = 4___16; //
+
+    let fail24 = 12.34_64;
+    let fail25 = 1E2_32;
+    let fail26 = 43E7_64;
+    let fail27 = 243E17_32;
+    #[allow(overflowing_literals)]
+    let fail28 = 241251235E723_64;
+    let fail29 = 42279.911_32;
+
+    let _ = 1.12345E1_32;
+}
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
new file mode 100644
index 00000000000..48a7ae90494
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
@@ -0,0 +1,82 @@
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:6:18
+   |
+LL |     let fail14 = 2_32;
+   |                  ^^^^ help: did you mean to write: `2_i32`
+   |
+   = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:7:18
+   |
+LL |     let fail15 = 4_64;
+   |                  ^^^^ help: did you mean to write: `4_i64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:8:18
+   |
+LL |     let fail16 = 7_8; //
+   |                  ^^^ help: did you mean to write: `7_i8`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:9:18
+   |
+LL |     let fail17 = 23_16; //
+   |                  ^^^^^ help: did you mean to write: `23_i16`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:12:18
+   |
+LL |     let fail20 = 2__8; //
+   |                  ^^^^ help: did you mean to write: `2_i8`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:13:18
+   |
+LL |     let fail21 = 4___16; //
+   |                  ^^^^^^ help: did you mean to write: `4_i16`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:15:18
+   |
+LL |     let fail24 = 12.34_64;
+   |                  ^^^^^^^^ help: did you mean to write: `12.34_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:16:18
+   |
+LL |     let fail25 = 1E2_32;
+   |                  ^^^^^^ help: did you mean to write: `1E2_f32`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:17:18
+   |
+LL |     let fail26 = 43E7_64;
+   |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:18:18
+   |
+LL |     let fail27 = 243E17_32;
+   |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:20:18
+   |
+LL |     let fail28 = 241251235E723_64;
+   |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:21:18
+   |
+LL |     let fail29 = 42279.911_32;
+   |                  ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:23:13
+   |
+LL |     let _ = 1.12345E1_32;
+   |             ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/module_inception.rs b/src/tools/clippy/tests/ui/module_inception.rs
new file mode 100644
index 00000000000..a23aba9164a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/module_inception.rs
@@ -0,0 +1,21 @@
+#![warn(clippy::module_inception)]
+
+mod foo {
+    mod bar {
+        mod bar {
+            mod foo {}
+        }
+        mod foo {}
+    }
+    mod foo {
+        mod bar {}
+    }
+}
+
+// No warning. See <https://github.com/rust-lang/rust-clippy/issues/1220>.
+mod bar {
+    #[allow(clippy::module_inception)]
+    mod bar {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/module_inception.stderr b/src/tools/clippy/tests/ui/module_inception.stderr
new file mode 100644
index 00000000000..77564dce9eb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/module_inception.stderr
@@ -0,0 +1,20 @@
+error: module has the same name as its containing module
+  --> $DIR/module_inception.rs:5:9
+   |
+LL | /         mod bar {
+LL | |             mod foo {}
+LL | |         }
+   | |_________^
+   |
+   = note: `-D clippy::module-inception` implied by `-D warnings`
+
+error: module has the same name as its containing module
+  --> $DIR/module_inception.rs:10:5
+   |
+LL | /     mod foo {
+LL | |         mod bar {}
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs
new file mode 100644
index 00000000000..669bf01a84c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs
@@ -0,0 +1,26 @@
+// compile-flags: --test
+
+#![warn(clippy::module_name_repetitions)]
+#![allow(dead_code)]
+
+mod foo {
+    pub fn foo() {}
+    pub fn foo_bar() {}
+    pub fn bar_foo() {}
+    pub struct FooCake {}
+    pub enum CakeFoo {}
+    pub struct Foo7Bar;
+
+    // Should not warn
+    pub struct Foobar;
+}
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn it_works() {
+        assert_eq!(2 + 2, 4);
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.stderr b/src/tools/clippy/tests/ui/module_name_repetitions.stderr
new file mode 100644
index 00000000000..bdd217a969c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.stderr
@@ -0,0 +1,34 @@
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:8:5
+   |
+LL |     pub fn foo_bar() {}
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
+
+error: item name ends with its containing module's name
+  --> $DIR/module_name_repetitions.rs:9:5
+   |
+LL |     pub fn bar_foo() {}
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:10:5
+   |
+LL |     pub struct FooCake {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: item name ends with its containing module's name
+  --> $DIR/module_name_repetitions.rs:11:5
+   |
+LL |     pub enum CakeFoo {}
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:12:5
+   |
+LL |     pub struct Foo7Bar;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
new file mode 100644
index 00000000000..b010b0dbdfa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
@@ -0,0 +1,36 @@
+#![warn(clippy::modulo_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::modulo_one
+)]
+
+fn main() {
+    // Lint when both sides are const and of the opposite sign
+    -1.6 % 2.1;
+    1.6 % -2.1;
+    (1.1 - 2.3) % (1.1 + 2.3);
+    (1.1 + 2.3) % (1.1 - 2.3);
+
+    // Lint on floating point numbers
+    let a_f32: f32 = -1.6;
+    let mut b_f32: f32 = 2.1;
+    a_f32 % b_f32;
+    b_f32 % a_f32;
+    b_f32 %= a_f32;
+
+    let a_f64: f64 = -1.6;
+    let mut b_f64: f64 = 2.1;
+    a_f64 % b_f64;
+    b_f64 % a_f64;
+    b_f64 %= a_f64;
+
+    // No lint when both sides are const and of the same sign
+    1.6 % 2.1;
+    -1.6 % -2.1;
+    (1.1 + 2.3) % (-1.1 + 2.3);
+    (-1.1 - 2.3) % (1.1 - 2.3);
+}
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
new file mode 100644
index 00000000000..7bfdb0bde60
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
@@ -0,0 +1,83 @@
+error: you are using modulo operator on constants with different signs: `-1.600 % 2.100`
+  --> $DIR/modulo_arithmetic_float.rs:13:5
+   |
+LL |     -1.6 % 2.1;
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on constants with different signs: `1.600 % -2.100`
+  --> $DIR/modulo_arithmetic_float.rs:14:5
+   |
+LL |     1.6 % -2.1;
+   |     ^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on constants with different signs: `-1.200 % 3.400`
+  --> $DIR/modulo_arithmetic_float.rs:15:5
+   |
+LL |     (1.1 - 2.3) % (1.1 + 2.3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on constants with different signs: `3.400 % -1.200`
+  --> $DIR/modulo_arithmetic_float.rs:16:5
+   |
+LL |     (1.1 + 2.3) % (1.1 - 2.3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:21:5
+   |
+LL |     a_f32 % b_f32;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:22:5
+   |
+LL |     b_f32 % a_f32;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:23:5
+   |
+LL |     b_f32 %= a_f32;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:27:5
+   |
+LL |     a_f64 % b_f64;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:28:5
+   |
+LL |     b_f64 % a_f64;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_float.rs:29:5
+   |
+LL |     b_f64 %= a_f64;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
new file mode 100644
index 00000000000..779d035c5f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
@@ -0,0 +1,90 @@
+#![warn(clippy::modulo_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::modulo_one
+)]
+
+fn main() {
+    // Lint on signed integral numbers
+    let a = -1;
+    let mut b = 2;
+    a % b;
+    b % a;
+    b %= a;
+
+    let a_i8: i8 = 1;
+    let mut b_i8: i8 = 2;
+    a_i8 % b_i8;
+    b_i8 %= a_i8;
+
+    let a_i16: i16 = 1;
+    let mut b_i16: i16 = 2;
+    a_i16 % b_i16;
+    b_i16 %= a_i16;
+
+    let a_i32: i32 = 1;
+    let mut b_i32: i32 = 2;
+    a_i32 % b_i32;
+    b_i32 %= a_i32;
+
+    let a_i64: i64 = 1;
+    let mut b_i64: i64 = 2;
+    a_i64 % b_i64;
+    b_i64 %= a_i64;
+
+    let a_i128: i128 = 1;
+    let mut b_i128: i128 = 2;
+    a_i128 % b_i128;
+    b_i128 %= a_i128;
+
+    let a_isize: isize = 1;
+    let mut b_isize: isize = 2;
+    a_isize % b_isize;
+    b_isize %= a_isize;
+
+    let a = 1;
+    let mut b = 2;
+    a % b;
+    b %= a;
+
+    // No lint on unsigned integral value
+    let a_u8: u8 = 17;
+    let b_u8: u8 = 3;
+    a_u8 % b_u8;
+    let mut a_u8: u8 = 1;
+    a_u8 %= 2;
+
+    let a_u16: u16 = 17;
+    let b_u16: u16 = 3;
+    a_u16 % b_u16;
+    let mut a_u16: u16 = 1;
+    a_u16 %= 2;
+
+    let a_u32: u32 = 17;
+    let b_u32: u32 = 3;
+    a_u32 % b_u32;
+    let mut a_u32: u32 = 1;
+    a_u32 %= 2;
+
+    let a_u64: u64 = 17;
+    let b_u64: u64 = 3;
+    a_u64 % b_u64;
+    let mut a_u64: u64 = 1;
+    a_u64 %= 2;
+
+    let a_u128: u128 = 17;
+    let b_u128: u128 = 3;
+    a_u128 % b_u128;
+    let mut a_u128: u128 = 1;
+    a_u128 %= 2;
+
+    let a_usize: usize = 17;
+    let b_usize: usize = 3;
+    a_usize % b_usize;
+    let mut a_usize: usize = 1;
+    a_usize %= 2;
+}
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
new file mode 100644
index 00000000000..e863b838699
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
@@ -0,0 +1,156 @@
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:15:5
+   |
+LL |     a % b;
+   |     ^^^^^
+   |
+   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:16:5
+   |
+LL |     b % a;
+   |     ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:17:5
+   |
+LL |     b %= a;
+   |     ^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:21:5
+   |
+LL |     a_i8 % b_i8;
+   |     ^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:22:5
+   |
+LL |     b_i8 %= a_i8;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:26:5
+   |
+LL |     a_i16 % b_i16;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:27:5
+   |
+LL |     b_i16 %= a_i16;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:31:5
+   |
+LL |     a_i32 % b_i32;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:32:5
+   |
+LL |     b_i32 %= a_i32;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:36:5
+   |
+LL |     a_i64 % b_i64;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:37:5
+   |
+LL |     b_i64 %= a_i64;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:41:5
+   |
+LL |     a_i128 % b_i128;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:42:5
+   |
+LL |     b_i128 %= a_i128;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:46:5
+   |
+LL |     a_isize % b_isize;
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:47:5
+   |
+LL |     b_isize %= a_isize;
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:51:5
+   |
+LL |     a % b;
+   |     ^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on types that might have different signs
+  --> $DIR/modulo_arithmetic_integral.rs:52:5
+   |
+LL |     b %= a;
+   |     ^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs
new file mode 100644
index 00000000000..57a96692c00
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs
@@ -0,0 +1,44 @@
+#![warn(clippy::modulo_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::modulo_one
+)]
+
+fn main() {
+    // Lint when both sides are const and of the opposite sign
+    -1 % 2;
+    1 % -2;
+    (1 - 2) % (1 + 2);
+    (1 + 2) % (1 - 2);
+    35 * (7 - 4 * 2) % (-500 * -600);
+
+    -1i8 % 2i8;
+    1i8 % -2i8;
+    -1i16 % 2i16;
+    1i16 % -2i16;
+    -1i32 % 2i32;
+    1i32 % -2i32;
+    -1i64 % 2i64;
+    1i64 % -2i64;
+    -1i128 % 2i128;
+    1i128 % -2i128;
+    -1isize % 2isize;
+    1isize % -2isize;
+
+    // No lint when both sides are const and of the same sign
+    1 % 2;
+    -1 % -2;
+    (1 + 2) % (-1 + 2);
+    (-1 - 2) % (1 - 2);
+
+    1u8 % 2u8;
+    1u16 % 2u16;
+    1u32 % 2u32;
+    1u64 % 2u64;
+    1u128 % 2u128;
+    1usize % 2usize;
+}
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
new file mode 100644
index 00000000000..de328bb75fe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
@@ -0,0 +1,156 @@
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:13:5
+   |
+LL |     -1 % 2;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:14:5
+   |
+LL |     1 % -2;
+   |     ^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 3`
+  --> $DIR/modulo_arithmetic_integral_const.rs:15:5
+   |
+LL |     (1 - 2) % (1 + 2);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `3 % -1`
+  --> $DIR/modulo_arithmetic_integral_const.rs:16:5
+   |
+LL |     (1 + 2) % (1 - 2);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-35 % 300000`
+  --> $DIR/modulo_arithmetic_integral_const.rs:17:5
+   |
+LL |     35 * (7 - 4 * 2) % (-500 * -600);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:19:5
+   |
+LL |     -1i8 % 2i8;
+   |     ^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:20:5
+   |
+LL |     1i8 % -2i8;
+   |     ^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:21:5
+   |
+LL |     -1i16 % 2i16;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:22:5
+   |
+LL |     1i16 % -2i16;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:23:5
+   |
+LL |     -1i32 % 2i32;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:24:5
+   |
+LL |     1i32 % -2i32;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:25:5
+   |
+LL |     -1i64 % 2i64;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:26:5
+   |
+LL |     1i64 % -2i64;
+   |     ^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:27:5
+   |
+LL |     -1i128 % 2i128;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:28:5
+   |
+LL |     1i128 % -2i128;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `-1 % 2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:29:5
+   |
+LL |     -1isize % 2isize;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: you are using modulo operator on constants with different signs: `1 % -2`
+  --> $DIR/modulo_arithmetic_integral_const.rs:30:5
+   |
+LL |     1isize % -2isize;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+   = note: or consider using `rem_euclid` or similar function
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/modulo_one.rs b/src/tools/clippy/tests/ui/modulo_one.rs
new file mode 100644
index 00000000000..cc8c8e7cdae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_one.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::modulo_one)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+static STATIC_ONE: usize = 2 - 1;
+
+fn main() {
+    10 % 1;
+    10 % 2;
+
+    const ONE: u32 = 1 * 1;
+
+    2 % ONE;
+    5 % STATIC_ONE;
+}
diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr
new file mode 100644
index 00000000000..6bee68360b6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/modulo_one.stderr
@@ -0,0 +1,30 @@
+error: any number modulo 1 will be 0
+  --> $DIR/modulo_one.rs:7:5
+   |
+LL |     10 % 1;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::modulo-one` implied by `-D warnings`
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/modulo_one.rs:10:22
+   |
+LL |     const ONE: u32 = 1 * 1;
+   |                      ^^^^^
+   |
+   = note: `-D clippy::identity-op` implied by `-D warnings`
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/modulo_one.rs:10:22
+   |
+LL |     const ONE: u32 = 1 * 1;
+   |                      ^^^^^
+
+error: any number modulo 1 will be 0
+  --> $DIR/modulo_one.rs:12:5
+   |
+LL |     2 % ONE;
+   |     ^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
new file mode 100644
index 00000000000..9556f6f82cc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -0,0 +1,93 @@
+// run-rustfix
+#![feature(never_type)]
+#![allow(unused_mut, clippy::redundant_allocation)]
+#![warn(clippy::must_use_candidate)]
+use std::rc::Rc;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+
+pub struct MyAtomic(AtomicBool);
+pub struct MyPure;
+
+#[must_use] pub fn pure(i: u8) -> u8 {
+    i
+}
+
+impl MyPure {
+    #[must_use] pub fn inherent_pure(&self) -> u8 {
+        0
+    }
+}
+
+pub trait MyPureTrait {
+    fn trait_pure(&self, i: u32) -> u32 {
+        self.trait_impl_pure(i) + 1
+    }
+
+    fn trait_impl_pure(&self, i: u32) -> u32;
+}
+
+impl MyPureTrait for MyPure {
+    fn trait_impl_pure(&self, i: u32) -> u32 {
+        i
+    }
+}
+
+pub fn without_result() {
+    // OK
+}
+
+pub fn impure_primitive(i: &mut u8) -> u8 {
+    *i
+}
+
+pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool {
+    f(0)
+}
+
+#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
+    true
+}
+
+pub fn quoth_the_raven(_more: !) -> u32 {
+    unimplemented!();
+}
+
+pub fn atomics(b: &AtomicBool) -> bool {
+    b.load(Ordering::SeqCst)
+}
+
+#[must_use] pub fn rcd(_x: Rc<u32>) -> bool {
+    true
+}
+
+pub fn rcmut(_x: Rc<&mut u32>) -> bool {
+    true
+}
+
+#[must_use] pub fn arcd(_x: Arc<u32>) -> bool {
+    false
+}
+
+pub fn inner_types(_m: &MyAtomic) -> bool {
+    true
+}
+
+static mut COUNTER: usize = 0;
+
+/// # Safety
+///
+/// Don't ever call this from multiple threads
+pub unsafe fn mutates_static() -> usize {
+    COUNTER += 1;
+    COUNTER
+}
+
+#[no_mangle]
+pub fn unmangled(i: bool) -> bool {
+    !i
+}
+
+fn main() {
+    assert_eq!(1, pure(1));
+}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
new file mode 100644
index 00000000000..37324220171
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -0,0 +1,93 @@
+// run-rustfix
+#![feature(never_type)]
+#![allow(unused_mut, clippy::redundant_allocation)]
+#![warn(clippy::must_use_candidate)]
+use std::rc::Rc;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+
+pub struct MyAtomic(AtomicBool);
+pub struct MyPure;
+
+pub fn pure(i: u8) -> u8 {
+    i
+}
+
+impl MyPure {
+    pub fn inherent_pure(&self) -> u8 {
+        0
+    }
+}
+
+pub trait MyPureTrait {
+    fn trait_pure(&self, i: u32) -> u32 {
+        self.trait_impl_pure(i) + 1
+    }
+
+    fn trait_impl_pure(&self, i: u32) -> u32;
+}
+
+impl MyPureTrait for MyPure {
+    fn trait_impl_pure(&self, i: u32) -> u32 {
+        i
+    }
+}
+
+pub fn without_result() {
+    // OK
+}
+
+pub fn impure_primitive(i: &mut u8) -> u8 {
+    *i
+}
+
+pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool {
+    f(0)
+}
+
+pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
+    true
+}
+
+pub fn quoth_the_raven(_more: !) -> u32 {
+    unimplemented!();
+}
+
+pub fn atomics(b: &AtomicBool) -> bool {
+    b.load(Ordering::SeqCst)
+}
+
+pub fn rcd(_x: Rc<u32>) -> bool {
+    true
+}
+
+pub fn rcmut(_x: Rc<&mut u32>) -> bool {
+    true
+}
+
+pub fn arcd(_x: Arc<u32>) -> bool {
+    false
+}
+
+pub fn inner_types(_m: &MyAtomic) -> bool {
+    true
+}
+
+static mut COUNTER: usize = 0;
+
+/// # Safety
+///
+/// Don't ever call this from multiple threads
+pub unsafe fn mutates_static() -> usize {
+    COUNTER += 1;
+    COUNTER
+}
+
+#[no_mangle]
+pub fn unmangled(i: bool) -> bool {
+    !i
+}
+
+fn main() {
+    assert_eq!(1, pure(1));
+}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr
new file mode 100644
index 00000000000..0fa3849d03b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr
@@ -0,0 +1,34 @@
+error: this function could have a `#[must_use]` attribute
+  --> $DIR/must_use_candidates.rs:12:1
+   |
+LL | pub fn pure(i: u8) -> u8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
+   |
+   = note: `-D clippy::must-use-candidate` implied by `-D warnings`
+
+error: this method could have a `#[must_use]` attribute
+  --> $DIR/must_use_candidates.rs:17:5
+   |
+LL |     pub fn inherent_pure(&self) -> u8 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
+
+error: this function could have a `#[must_use]` attribute
+  --> $DIR/must_use_candidates.rs:48:1
+   |
+LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
+
+error: this function could have a `#[must_use]` attribute
+  --> $DIR/must_use_candidates.rs:60:1
+   |
+LL | pub fn rcd(_x: Rc<u32>) -> bool {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
+
+error: this function could have a `#[must_use]` attribute
+  --> $DIR/must_use_candidates.rs:68:1
+   |
+LL | pub fn arcd(_x: Arc<u32>) -> bool {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed
new file mode 100644
index 00000000000..6c9aa434ac0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_unit.fixed
@@ -0,0 +1,26 @@
+//run-rustfix
+// aux-build:macro_rules.rs
+
+#![warn(clippy::must_use_unit)]
+#![allow(clippy::unused_unit)]
+
+#[macro_use]
+extern crate macro_rules;
+
+
+pub fn must_use_default() {}
+
+
+pub fn must_use_unit() -> () {}
+
+
+pub fn must_use_with_note() {}
+
+fn main() {
+    must_use_default();
+    must_use_unit();
+    must_use_with_note();
+
+    // We should not lint in external macros
+    must_use_unit!();
+}
diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs
new file mode 100644
index 00000000000..8a395dc284d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_unit.rs
@@ -0,0 +1,26 @@
+//run-rustfix
+// aux-build:macro_rules.rs
+
+#![warn(clippy::must_use_unit)]
+#![allow(clippy::unused_unit)]
+
+#[macro_use]
+extern crate macro_rules;
+
+#[must_use]
+pub fn must_use_default() {}
+
+#[must_use]
+pub fn must_use_unit() -> () {}
+
+#[must_use = "With note"]
+pub fn must_use_with_note() {}
+
+fn main() {
+    must_use_default();
+    must_use_unit();
+    must_use_with_note();
+
+    // We should not lint in external macros
+    must_use_unit!();
+}
diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr
new file mode 100644
index 00000000000..15e0906b66b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_unit.stderr
@@ -0,0 +1,28 @@
+error: this unit-returning function has a `#[must_use]` attribute
+  --> $DIR/must_use_unit.rs:11:1
+   |
+LL | #[must_use]
+   | ----------- help: remove the attribute
+LL | pub fn must_use_default() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::must-use-unit` implied by `-D warnings`
+
+error: this unit-returning function has a `#[must_use]` attribute
+  --> $DIR/must_use_unit.rs:14:1
+   |
+LL | #[must_use]
+   | ----------- help: remove the attribute
+LL | pub fn must_use_unit() -> () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this unit-returning function has a `#[must_use]` attribute
+  --> $DIR/must_use_unit.rs:17:1
+   |
+LL | #[must_use = "With note"]
+   | ------------------------- help: remove the attribute
+LL | pub fn must_use_with_note() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.rs b/src/tools/clippy/tests/ui/mut_from_ref.rs
new file mode 100644
index 00000000000..a9a04c8f56b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_from_ref.rs
@@ -0,0 +1,46 @@
+#![allow(unused)]
+#![warn(clippy::mut_from_ref)]
+
+struct Foo;
+
+impl Foo {
+    fn this_wont_hurt_a_bit(&self) -> &mut Foo {
+        unimplemented!()
+    }
+}
+
+trait Ouch {
+    fn ouch(x: &Foo) -> &mut Foo;
+}
+
+impl Ouch for Foo {
+    fn ouch(x: &Foo) -> &mut Foo {
+        unimplemented!()
+    }
+}
+
+fn fail(x: &u32) -> &mut u16 {
+    unimplemented!()
+}
+
+fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
+    unimplemented!()
+}
+
+fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
+    unimplemented!()
+}
+
+// this is OK, because the result borrows y
+fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 {
+    unimplemented!()
+}
+
+// this is also OK, because the result could borrow y
+fn also_works<'a>(x: &'a u32, y: &'a mut u32) -> &'a mut u32 {
+    unimplemented!()
+}
+
+fn main() {
+    //TODO
+}
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.stderr b/src/tools/clippy/tests/ui/mut_from_ref.stderr
new file mode 100644
index 00000000000..4787999920b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_from_ref.stderr
@@ -0,0 +1,63 @@
+error: mutable borrow from immutable input(s)
+  --> $DIR/mut_from_ref.rs:7:39
+   |
+LL |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
+   |                                       ^^^^^^^^
+   |
+   = note: `-D clippy::mut-from-ref` implied by `-D warnings`
+note: immutable borrow here
+  --> $DIR/mut_from_ref.rs:7:29
+   |
+LL |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
+   |                             ^^^^^
+
+error: mutable borrow from immutable input(s)
+  --> $DIR/mut_from_ref.rs:13:25
+   |
+LL |     fn ouch(x: &Foo) -> &mut Foo;
+   |                         ^^^^^^^^
+   |
+note: immutable borrow here
+  --> $DIR/mut_from_ref.rs:13:16
+   |
+LL |     fn ouch(x: &Foo) -> &mut Foo;
+   |                ^^^^
+
+error: mutable borrow from immutable input(s)
+  --> $DIR/mut_from_ref.rs:22:21
+   |
+LL | fn fail(x: &u32) -> &mut u16 {
+   |                     ^^^^^^^^
+   |
+note: immutable borrow here
+  --> $DIR/mut_from_ref.rs:22:12
+   |
+LL | fn fail(x: &u32) -> &mut u16 {
+   |            ^^^^
+
+error: mutable borrow from immutable input(s)
+  --> $DIR/mut_from_ref.rs:26:50
+   |
+LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
+   |                                                  ^^^^^^^^^^^
+   |
+note: immutable borrow here
+  --> $DIR/mut_from_ref.rs:26:25
+   |
+LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
+   |                         ^^^^^^^
+
+error: mutable borrow from immutable input(s)
+  --> $DIR/mut_from_ref.rs:30:67
+   |
+LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
+   |                                                                   ^^^^^^^^^^^
+   |
+note: immutable borrow here
+  --> $DIR/mut_from_ref.rs:30:27
+   |
+LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
+   |                           ^^^^^^^     ^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs
new file mode 100644
index 00000000000..2d227e6654c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_key.rs
@@ -0,0 +1,55 @@
+use std::collections::{HashMap, HashSet};
+use std::hash::{Hash, Hasher};
+use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+
+struct Key(AtomicUsize);
+
+impl Clone for Key {
+    fn clone(&self) -> Self {
+        Key(AtomicUsize::new(self.0.load(Relaxed)))
+    }
+}
+
+impl PartialEq for Key {
+    fn eq(&self, other: &Self) -> bool {
+        self.0.load(Relaxed) == other.0.load(Relaxed)
+    }
+}
+
+impl Eq for Key {}
+
+impl Hash for Key {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        self.0.load(Relaxed).hash(h);
+    }
+}
+
+fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+    let _other: HashMap<Key, bool> = HashMap::new();
+    m.keys().cloned().collect()
+}
+
+fn this_is_ok(_m: &mut HashMap<usize, Key>) {}
+
+#[allow(unused)]
+trait Trait {
+    type AssociatedType;
+
+    fn trait_fn(&self, set: std::collections::HashSet<Self::AssociatedType>);
+}
+
+fn generics_are_ok_too<K>(_m: &mut HashSet<K>) {
+    // nothing to see here, move along
+}
+
+fn tuples<U>(_m: &mut HashMap<((), U), ()>) {}
+
+fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
+
+fn main() {
+    let _ = should_not_take_this_arg(&mut HashMap::new(), 1);
+    this_is_ok(&mut HashMap::new());
+    tuples::<Key>(&mut HashMap::new());
+    tuples::<()>(&mut HashMap::new());
+    tuples_bad::<()>(&mut HashMap::new());
+}
diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr
new file mode 100644
index 00000000000..8d6a259c7e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_key.stderr
@@ -0,0 +1,28 @@
+error: mutable key type
+  --> $DIR/mut_key.rs:27:32
+   |
+LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::mutable_key_type)]` on by default
+
+error: mutable key type
+  --> $DIR/mut_key.rs:27:72
+   |
+LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+   |                                                                        ^^^^^^^^^^^^
+
+error: mutable key type
+  --> $DIR/mut_key.rs:28:5
+   |
+LL |     let _other: HashMap<Key, bool> = HashMap::new();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable key type
+  --> $DIR/mut_key.rs:47:22
+   |
+LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs
new file mode 100644
index 00000000000..8965cef66de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_mut.rs
@@ -0,0 +1,49 @@
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
+#![warn(clippy::mut_mut)]
+
+fn fun(x: &mut &mut u32) -> bool {
+    **x > 0
+}
+
+fn less_fun(x: *mut *mut u32) {
+    let y = x;
+}
+
+macro_rules! mut_ptr {
+    ($p:expr) => {
+        &mut $p
+    };
+}
+
+#[allow(unused_mut, unused_variables)]
+fn main() {
+    let mut x = &mut &mut 1u32;
+    {
+        let mut y = &mut x;
+    }
+
+    if fun(x) {
+        let y: &mut &mut u32 = &mut &mut 2;
+        **y + **x;
+    }
+
+    if fun(x) {
+        let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+        ***y + **x;
+    }
+
+    let mut z = mut_ptr!(&mut 3u32);
+}
+
+fn issue939() {
+    let array = [5, 6, 7, 8, 9];
+    let mut args = array.iter().skip(2);
+    for &arg in &mut args {
+        println!("{}", arg);
+    }
+
+    let args = &mut args;
+    for arg in args {
+        println!(":{}", arg);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr
new file mode 100644
index 00000000000..44e81422714
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_mut.stderr
@@ -0,0 +1,63 @@
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:4:11
+   |
+LL | fn fun(x: &mut &mut u32) -> bool {
+   |           ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mut-mut` implied by `-D warnings`
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:20:17
+   |
+LL |     let mut x = &mut &mut 1u32;
+   |                 ^^^^^^^^^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:14:9
+   |
+LL |         &mut $p
+   |         ^^^^^^^
+...
+LL |     let mut z = mut_ptr!(&mut 3u32);
+   |                 ------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this expression mutably borrows a mutable reference. Consider reborrowing
+  --> $DIR/mut_mut.rs:22:21
+   |
+LL |         let mut y = &mut x;
+   |                     ^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:26:32
+   |
+LL |         let y: &mut &mut u32 = &mut &mut 2;
+   |                                ^^^^^^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:26:16
+   |
+LL |         let y: &mut &mut u32 = &mut &mut 2;
+   |                ^^^^^^^^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:31:37
+   |
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                                     ^^^^^^^^^^^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:31:16
+   |
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                ^^^^^^^^^^^^^^^^^^
+
+error: generally you want to avoid `&mut &mut _` if possible
+  --> $DIR/mut_mut.rs:31:21
+   |
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                     ^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_range_bound.rs b/src/tools/clippy/tests/ui/mut_range_bound.rs
new file mode 100644
index 00000000000..1348dd2a3d8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_range_bound.rs
@@ -0,0 +1,63 @@
+#![allow(unused)]
+
+fn main() {
+    mut_range_bound_upper();
+    mut_range_bound_lower();
+    mut_range_bound_both();
+    mut_range_bound_no_mutation();
+    immut_range_bound();
+    mut_borrow_range_bound();
+    immut_borrow_range_bound();
+}
+
+fn mut_range_bound_upper() {
+    let mut m = 4;
+    for i in 0..m {
+        m = 5;
+    } // warning
+}
+
+fn mut_range_bound_lower() {
+    let mut m = 4;
+    for i in m..10 {
+        m *= 2;
+    } // warning
+}
+
+fn mut_range_bound_both() {
+    let mut m = 4;
+    let mut n = 6;
+    for i in m..n {
+        m = 5;
+        n = 7;
+    } // warning (1 for each mutated bound)
+}
+
+fn mut_range_bound_no_mutation() {
+    let mut m = 4;
+    for i in 0..m {
+        continue;
+    } // no warning
+}
+
+fn mut_borrow_range_bound() {
+    let mut m = 4;
+    for i in 0..m {
+        let n = &mut m; // warning
+        *n += 1;
+    }
+}
+
+fn immut_borrow_range_bound() {
+    let mut m = 4;
+    for i in 0..m {
+        let n = &m; // should be no warning?
+    }
+}
+
+fn immut_range_bound() {
+    let m = 4;
+    for i in 0..m {
+        continue;
+    } // no warning
+}
diff --git a/src/tools/clippy/tests/ui/mut_range_bound.stderr b/src/tools/clippy/tests/ui/mut_range_bound.stderr
new file mode 100644
index 00000000000..0eeb76e0ec5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_range_bound.stderr
@@ -0,0 +1,34 @@
+error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
+  --> $DIR/mut_range_bound.rs:16:9
+   |
+LL |         m = 5;
+   |         ^
+   |
+   = note: `-D clippy::mut-range-bound` implied by `-D warnings`
+
+error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
+  --> $DIR/mut_range_bound.rs:23:9
+   |
+LL |         m *= 2;
+   |         ^
+
+error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
+  --> $DIR/mut_range_bound.rs:31:9
+   |
+LL |         m = 5;
+   |         ^
+
+error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
+  --> $DIR/mut_range_bound.rs:32:9
+   |
+LL |         n = 7;
+   |         ^
+
+error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
+  --> $DIR/mut_range_bound.rs:46:22
+   |
+LL |         let n = &mut m; // warning
+   |                      ^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs
new file mode 100644
index 00000000000..73906121c40
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_reference.rs
@@ -0,0 +1,43 @@
+#![allow(unused_variables)]
+
+fn takes_an_immutable_reference(a: &i32) {}
+fn takes_a_mutable_reference(a: &mut i32) {}
+
+struct MyStruct;
+
+impl MyStruct {
+    fn takes_an_immutable_reference(&self, a: &i32) {}
+
+    fn takes_a_mutable_reference(&self, a: &mut i32) {}
+}
+
+#[warn(clippy::unnecessary_mut_passed)]
+fn main() {
+    // Functions
+    takes_an_immutable_reference(&mut 42);
+    let as_ptr: fn(&i32) = takes_an_immutable_reference;
+    as_ptr(&mut 42);
+
+    // Methods
+    let my_struct = MyStruct;
+    my_struct.takes_an_immutable_reference(&mut 42);
+
+    // No error
+
+    // Functions
+    takes_an_immutable_reference(&42);
+    let as_ptr: fn(&i32) = takes_an_immutable_reference;
+    as_ptr(&42);
+
+    takes_a_mutable_reference(&mut 42);
+    let as_ptr: fn(&mut i32) = takes_a_mutable_reference;
+    as_ptr(&mut 42);
+
+    let a = &mut 42;
+    takes_an_immutable_reference(a);
+
+    // Methods
+    my_struct.takes_an_immutable_reference(&42);
+    my_struct.takes_a_mutable_reference(&mut 42);
+    my_struct.takes_an_immutable_reference(a);
+}
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
new file mode 100644
index 00000000000..fa8c82ae0f3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -0,0 +1,22 @@
+error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
+  --> $DIR/mut_reference.rs:17:34
+   |
+LL |     takes_an_immutable_reference(&mut 42);
+   |                                  ^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
+
+error: The function/method `as_ptr` doesn't need a mutable reference
+  --> $DIR/mut_reference.rs:19:12
+   |
+LL |     as_ptr(&mut 42);
+   |            ^^^^^^^
+
+error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
+  --> $DIR/mut_reference.rs:23:44
+   |
+LL |     my_struct.takes_an_immutable_reference(&mut 42);
+   |                                            ^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.rs b/src/tools/clippy/tests/ui/mutex_atomic.rs
new file mode 100644
index 00000000000..b9d78b7f479
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mutex_atomic.rs
@@ -0,0 +1,15 @@
+#![warn(clippy::all)]
+#![warn(clippy::mutex_integer)]
+
+fn main() {
+    use std::sync::Mutex;
+    Mutex::new(true);
+    Mutex::new(5usize);
+    Mutex::new(9isize);
+    let mut x = 4u32;
+    Mutex::new(&x as *const u32);
+    Mutex::new(&mut x as *mut u32);
+    Mutex::new(0u32);
+    Mutex::new(0i32);
+    Mutex::new(0f32); // there are no float atomics, so this should not lint
+}
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr
new file mode 100644
index 00000000000..7dac0865855
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr
@@ -0,0 +1,48 @@
+error: Consider using an `AtomicBool` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:6:5
+   |
+LL |     Mutex::new(true);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mutex-atomic` implied by `-D warnings`
+
+error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:7:5
+   |
+LL |     Mutex::new(5usize);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:8:5
+   |
+LL |     Mutex::new(9isize);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:10:5
+   |
+LL |     Mutex::new(&x as *const u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:11:5
+   |
+LL |     Mutex::new(&mut x as *mut u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:12:5
+   |
+LL |     Mutex::new(0u32);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mutex-integer` implied by `-D warnings`
+
+error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+  --> $DIR/mutex_atomic.rs:13:5
+   |
+LL |     Mutex::new(0i32);
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
new file mode 100644
index 00000000000..567dbc54100
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
@@ -0,0 +1,98 @@
+// run-rustfix
+
+#![warn(clippy::needless_bool)]
+#![allow(
+    unused,
+    dead_code,
+    clippy::no_effect,
+    clippy::if_same_then_else,
+    clippy::needless_return
+)]
+
+use std::cell::Cell;
+
+macro_rules! bool_comparison_trigger {
+    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
+
+        #[derive(Clone)]
+        pub struct Trigger {
+            $($i: (Cell<bool>, bool, bool)),+
+        }
+
+        #[allow(dead_code)]
+        impl Trigger {
+            pub fn trigger(&self, key: &str) -> bool {
+                $(
+                    if let stringify!($i) = key {
+                        return self.$i.1 && self.$i.2 == $def;
+                    }
+                 )+
+                false
+            }
+        }
+    )
+}
+
+fn main() {
+    let x = true;
+    let y = false;
+    x;
+    !x;
+    !(x && y);
+    if x {
+        x
+    } else {
+        false
+    }; // would also be questionable, but we don't catch this yet
+    bool_ret3(x);
+    bool_ret4(x);
+    bool_ret5(x, x);
+    bool_ret6(x, x);
+    needless_bool(x);
+    needless_bool2(x);
+    needless_bool3(x);
+}
+
+fn bool_ret3(x: bool) -> bool {
+    return x;
+}
+
+fn bool_ret4(x: bool) -> bool {
+    return !x;
+}
+
+fn bool_ret5(x: bool, y: bool) -> bool {
+    return x && y;
+}
+
+fn bool_ret6(x: bool, y: bool) -> bool {
+    return !(x && y);
+}
+
+fn needless_bool(x: bool) {
+    if x {};
+}
+
+fn needless_bool2(x: bool) {
+    if !x {};
+}
+
+fn needless_bool3(x: bool) {
+    bool_comparison_trigger! {
+        test_one:   false, false;
+        test_three: false, false;
+        test_two:   true, true;
+    }
+
+    if x {};
+    if !x {};
+}
+
+fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
+    let b = false;
+    let returns_bool = || false;
+
+    let x = if b {
+        true
+    } else { !returns_bool() };
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
new file mode 100644
index 00000000000..10126ad4dbb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
@@ -0,0 +1,130 @@
+// run-rustfix
+
+#![warn(clippy::needless_bool)]
+#![allow(
+    unused,
+    dead_code,
+    clippy::no_effect,
+    clippy::if_same_then_else,
+    clippy::needless_return
+)]
+
+use std::cell::Cell;
+
+macro_rules! bool_comparison_trigger {
+    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
+
+        #[derive(Clone)]
+        pub struct Trigger {
+            $($i: (Cell<bool>, bool, bool)),+
+        }
+
+        #[allow(dead_code)]
+        impl Trigger {
+            pub fn trigger(&self, key: &str) -> bool {
+                $(
+                    if let stringify!($i) = key {
+                        return self.$i.1 && self.$i.2 == $def;
+                    }
+                 )+
+                false
+            }
+        }
+    )
+}
+
+fn main() {
+    let x = true;
+    let y = false;
+    if x {
+        true
+    } else {
+        false
+    };
+    if x {
+        false
+    } else {
+        true
+    };
+    if x && y {
+        false
+    } else {
+        true
+    };
+    if x {
+        x
+    } else {
+        false
+    }; // would also be questionable, but we don't catch this yet
+    bool_ret3(x);
+    bool_ret4(x);
+    bool_ret5(x, x);
+    bool_ret6(x, x);
+    needless_bool(x);
+    needless_bool2(x);
+    needless_bool3(x);
+}
+
+fn bool_ret3(x: bool) -> bool {
+    if x {
+        return true;
+    } else {
+        return false;
+    };
+}
+
+fn bool_ret4(x: bool) -> bool {
+    if x {
+        return false;
+    } else {
+        return true;
+    };
+}
+
+fn bool_ret5(x: bool, y: bool) -> bool {
+    if x && y {
+        return true;
+    } else {
+        return false;
+    };
+}
+
+fn bool_ret6(x: bool, y: bool) -> bool {
+    if x && y {
+        return false;
+    } else {
+        return true;
+    };
+}
+
+fn needless_bool(x: bool) {
+    if x == true {};
+}
+
+fn needless_bool2(x: bool) {
+    if x == false {};
+}
+
+fn needless_bool3(x: bool) {
+    bool_comparison_trigger! {
+        test_one:   false, false;
+        test_three: false, false;
+        test_two:   true, true;
+    }
+
+    if x == true {};
+    if x == false {};
+}
+
+fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
+    let b = false;
+    let returns_bool = || false;
+
+    let x = if b {
+        true
+    } else if returns_bool() {
+        false
+    } else {
+        true
+    };
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
new file mode 100644
index 00000000000..25abfb2a472
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
@@ -0,0 +1,111 @@
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:39:5
+   |
+LL | /     if x {
+LL | |         true
+LL | |     } else {
+LL | |         false
+LL | |     };
+   | |_____^ help: you can reduce it to: `x`
+   |
+   = note: `-D clippy::needless-bool` implied by `-D warnings`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:44:5
+   |
+LL | /     if x {
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `!x`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:49:5
+   |
+LL | /     if x && y {
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `!(x && y)`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:69:5
+   |
+LL | /     if x {
+LL | |         return true;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return x`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:77:5
+   |
+LL | /     if x {
+LL | |         return false;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return !x`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:85:5
+   |
+LL | /     if x && y {
+LL | |         return true;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return x && y`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:93:5
+   |
+LL | /     if x && y {
+LL | |         return false;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return !(x && y)`
+
+error: equality checks against true are unnecessary
+  --> $DIR/fixable.rs:101:8
+   |
+LL |     if x == true {};
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |
+   = note: `-D clippy::bool-comparison` implied by `-D warnings`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/fixable.rs:105:8
+   |
+LL |     if x == false {};
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: equality checks against true are unnecessary
+  --> $DIR/fixable.rs:115:8
+   |
+LL |     if x == true {};
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/fixable.rs:116:8
+   |
+LL |     if x == false {};
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/fixable.rs:125:12
+   |
+LL |       } else if returns_bool() {
+   |  ____________^
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `{ !returns_bool() }`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.rs b/src/tools/clippy/tests/ui/needless_bool/simple.rs
new file mode 100644
index 00000000000..e9f1428fc3a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool/simple.rs
@@ -0,0 +1,46 @@
+#![warn(clippy::needless_bool)]
+#![allow(
+    unused,
+    dead_code,
+    clippy::no_effect,
+    clippy::if_same_then_else,
+    clippy::needless_return
+)]
+
+fn main() {
+    let x = true;
+    let y = false;
+    if x {
+        true
+    } else {
+        true
+    };
+    if x {
+        false
+    } else {
+        false
+    };
+    if x {
+        x
+    } else {
+        false
+    }; // would also be questionable, but we don't catch this yet
+    bool_ret(x);
+    bool_ret2(x);
+}
+
+fn bool_ret(x: bool) -> bool {
+    if x {
+        return true;
+    } else {
+        return true;
+    };
+}
+
+fn bool_ret2(x: bool) -> bool {
+    if x {
+        return false;
+    } else {
+        return false;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.stderr b/src/tools/clippy/tests/ui/needless_bool/simple.stderr
new file mode 100644
index 00000000000..c57a8a042fb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool/simple.stderr
@@ -0,0 +1,44 @@
+error: this if-then-else expression will always return true
+  --> $DIR/simple.rs:13:5
+   |
+LL | /     if x {
+LL | |         true
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^
+   |
+   = note: `-D clippy::needless-bool` implied by `-D warnings`
+
+error: this if-then-else expression will always return false
+  --> $DIR/simple.rs:18:5
+   |
+LL | /     if x {
+LL | |         false
+LL | |     } else {
+LL | |         false
+LL | |     };
+   | |_____^
+
+error: this if-then-else expression will always return true
+  --> $DIR/simple.rs:33:5
+   |
+LL | /     if x {
+LL | |         return true;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^
+
+error: this if-then-else expression will always return false
+  --> $DIR/simple.rs:41:5
+   |
+LL | /     if x {
+LL | |         return false;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
new file mode 100644
index 00000000000..5ae4a0e79b9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -0,0 +1,61 @@
+// run-rustfix
+
+#![allow(clippy::needless_borrowed_reference)]
+
+fn x(y: &i32) -> i32 {
+    *y
+}
+
+#[warn(clippy::all, clippy::needless_borrow)]
+#[allow(unused_variables)]
+fn main() {
+    let a = 5;
+    let b = x(&a);
+    let c = x(&a);
+    let s = &String::from("hi");
+    let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not
+    let g_val = g(&Vec::new()); // should not error, because `&Vec<T>` derefs to `&[T]`
+    let vec = Vec::new();
+    let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
+    h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
+    if let Some(cake) = Some(&5) {}
+    let garbl = match 42 {
+        44 => &a,
+        45 => {
+            println!("foo");
+            &&a // FIXME: this should lint, too
+        },
+        46 => &a,
+        _ => panic!(),
+    };
+}
+
+fn f<T: Copy>(y: &T) -> T {
+    *y
+}
+
+fn g(y: &[u8]) -> u8 {
+    y[0]
+}
+
+trait Trait {}
+
+impl<'a> Trait for &'a str {}
+
+fn h(_: &dyn Trait) {}
+#[warn(clippy::needless_borrow)]
+#[allow(dead_code)]
+fn issue_1432() {
+    let mut v = Vec::<String>::new();
+    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+    let _ = v.iter().filter(|&a| a.is_empty());
+
+    let _ = v.iter().filter(|&a| a.is_empty());
+}
+
+#[allow(dead_code)]
+#[warn(clippy::needless_borrow)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
new file mode 100644
index 00000000000..1e281316c8a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -0,0 +1,61 @@
+// run-rustfix
+
+#![allow(clippy::needless_borrowed_reference)]
+
+fn x(y: &i32) -> i32 {
+    *y
+}
+
+#[warn(clippy::all, clippy::needless_borrow)]
+#[allow(unused_variables)]
+fn main() {
+    let a = 5;
+    let b = x(&a);
+    let c = x(&&a);
+    let s = &String::from("hi");
+    let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not
+    let g_val = g(&Vec::new()); // should not error, because `&Vec<T>` derefs to `&[T]`
+    let vec = Vec::new();
+    let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
+    h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
+    if let Some(ref cake) = Some(&5) {}
+    let garbl = match 42 {
+        44 => &a,
+        45 => {
+            println!("foo");
+            &&a // FIXME: this should lint, too
+        },
+        46 => &&a,
+        _ => panic!(),
+    };
+}
+
+fn f<T: Copy>(y: &T) -> T {
+    *y
+}
+
+fn g(y: &[u8]) -> u8 {
+    y[0]
+}
+
+trait Trait {}
+
+impl<'a> Trait for &'a str {}
+
+fn h(_: &dyn Trait) {}
+#[warn(clippy::needless_borrow)]
+#[allow(dead_code)]
+fn issue_1432() {
+    let mut v = Vec::<String>::new();
+    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+    let _ = v.iter().filter(|&ref a| a.is_empty());
+
+    let _ = v.iter().filter(|&a| a.is_empty());
+}
+
+#[allow(dead_code)]
+#[warn(clippy::needless_borrow)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
new file mode 100644
index 00000000000..0bfeda7914d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -0,0 +1,28 @@
+error: this expression borrows a reference that is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:14:15
+   |
+LL |     let c = x(&&a);
+   |               ^^^ help: change this to: `&a`
+   |
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow.rs:21:17
+   |
+LL |     if let Some(ref cake) = Some(&5) {}
+   |                 ^^^^^^^^ help: change this to: `cake`
+
+error: this expression borrows a reference that is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:28:15
+   |
+LL |         46 => &&a,
+   |               ^^^ help: change this to: `&a`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow.rs:51:31
+   |
+LL |     let _ = v.iter().filter(|&ref a| a.is_empty());
+   |                               ^^^^^ help: change this to: `a`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
new file mode 100644
index 00000000000..a0937a2c5f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#[warn(clippy::needless_borrowed_reference)]
+#[allow(unused_variables)]
+fn main() {
+    let mut v = Vec::<String>::new();
+    let _ = v.iter_mut().filter(|a| a.is_empty());
+    //                            ^ should be linted
+
+    let var = 3;
+    let thingy = Some(&var);
+    if let Some(&ref v) = thingy {
+        //          ^ should be linted
+    }
+
+    let mut var2 = 5;
+    let thingy2 = Some(&mut var2);
+    if let Some(&mut ref mut v) = thingy2 {
+        //          ^ should **not** be linted
+        // v is borrowed as mutable.
+        *v = 10;
+    }
+    if let Some(&mut ref v) = thingy2 {
+        //          ^ should **not** be linted
+        // here, v is borrowed as immutable.
+        // can't do that:
+        //*v = 15;
+    }
+}
+
+#[allow(dead_code)]
+enum Animal {
+    Cat(u64),
+    Dog(u64),
+}
+
+#[allow(unused_variables)]
+#[allow(dead_code)]
+fn foo(a: &Animal, b: &Animal) {
+    match (a, b) {
+        (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+        //                  ^    and   ^ should **not** be linted
+        (&Animal::Dog(ref a), &Animal::Dog(_)) => (), //              ^ should **not** be linted
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
new file mode 100644
index 00000000000..500ac448f0d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+
+#[warn(clippy::needless_borrowed_reference)]
+#[allow(unused_variables)]
+fn main() {
+    let mut v = Vec::<String>::new();
+    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+    //                            ^ should be linted
+
+    let var = 3;
+    let thingy = Some(&var);
+    if let Some(&ref v) = thingy {
+        //          ^ should be linted
+    }
+
+    let mut var2 = 5;
+    let thingy2 = Some(&mut var2);
+    if let Some(&mut ref mut v) = thingy2 {
+        //          ^ should **not** be linted
+        // v is borrowed as mutable.
+        *v = 10;
+    }
+    if let Some(&mut ref v) = thingy2 {
+        //          ^ should **not** be linted
+        // here, v is borrowed as immutable.
+        // can't do that:
+        //*v = 15;
+    }
+}
+
+#[allow(dead_code)]
+enum Animal {
+    Cat(u64),
+    Dog(u64),
+}
+
+#[allow(unused_variables)]
+#[allow(dead_code)]
+fn foo(a: &Animal, b: &Animal) {
+    match (a, b) {
+        (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+        //                  ^    and   ^ should **not** be linted
+        (&Animal::Dog(ref a), &Animal::Dog(_)) => (), //              ^ should **not** be linted
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr
new file mode 100644
index 00000000000..0a5cfb3db0b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr
@@ -0,0 +1,10 @@
+error: this pattern takes a reference on something that is being de-referenced
+  --> $DIR/needless_borrowed_ref.rs:7:34
+   |
+LL |     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+   |                                  ^^^^^^ help: try removing the `&ref` part and just keep: `a`
+   |
+   = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
new file mode 100644
index 00000000000..b4227eaf2f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![allow(unused, clippy::suspicious_map)]
+
+use std::collections::{BTreeSet, HashMap, HashSet};
+
+#[warn(clippy::needless_collect)]
+#[allow(unused_variables, clippy::iter_cloned_collect)]
+fn main() {
+    let sample = [1; 5];
+    let len = sample.iter().count();
+    if sample.iter().next().is_none() {
+        // Empty
+    }
+    sample.iter().cloned().any(|x| x == 1);
+    sample.iter().map(|x| (x, x)).count();
+    // Notice the `HashSet`--this should not be linted
+    sample.iter().collect::<HashSet<_>>().len();
+    // Neither should this
+    sample.iter().collect::<BTreeSet<_>>().len();
+}
diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs
new file mode 100644
index 00000000000..7ee603afeb0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_collect.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![allow(unused, clippy::suspicious_map)]
+
+use std::collections::{BTreeSet, HashMap, HashSet};
+
+#[warn(clippy::needless_collect)]
+#[allow(unused_variables, clippy::iter_cloned_collect)]
+fn main() {
+    let sample = [1; 5];
+    let len = sample.iter().collect::<Vec<_>>().len();
+    if sample.iter().collect::<Vec<_>>().is_empty() {
+        // Empty
+    }
+    sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    // Notice the `HashSet`--this should not be linted
+    sample.iter().collect::<HashSet<_>>().len();
+    // Neither should this
+    sample.iter().collect::<BTreeSet<_>>().len();
+}
diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr
new file mode 100644
index 00000000000..8884c8e1612
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_collect.stderr
@@ -0,0 +1,28 @@
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:11:28
+   |
+LL |     let len = sample.iter().collect::<Vec<_>>().len();
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
+   |
+LL |     if sample.iter().collect::<Vec<_>>().is_empty() {
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:15:27
+   |
+LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|x| x == 1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:16:34
+   |
+LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs
new file mode 100644
index 00000000000..5da95647f2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_continue.rs
@@ -0,0 +1,115 @@
+#![warn(clippy::needless_continue)]
+
+macro_rules! zero {
+    ($x:expr) => {
+        $x == 0
+    };
+}
+
+macro_rules! nonzero {
+    ($x:expr) => {
+        !zero!($x)
+    };
+}
+
+fn main() {
+    let mut i = 1;
+    while i < 10 {
+        i += 1;
+
+        if i % 2 == 0 && i % 3 == 0 {
+            println!("{}", i);
+            println!("{}", i + 1);
+            if i % 5 == 0 {
+                println!("{}", i + 2);
+            }
+            let i = 0;
+            println!("bar {} ", i);
+        } else {
+            continue;
+        }
+
+        println!("bleh");
+        {
+            println!("blah");
+        }
+
+        // some comments that also should ideally be included in the
+        // output of the lint suggestion if possible.
+        if !(!(i == 2) || !(i == 5)) {
+            println!("lama");
+        }
+
+        if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
+            continue;
+        } else {
+            println!("Blabber");
+            println!("Jabber");
+        }
+
+        println!("bleh");
+    }
+}
+
+mod issue_2329 {
+    fn condition() -> bool {
+        unimplemented!()
+    }
+    fn update_condition() {}
+
+    // only the outer loop has a label
+    fn foo() {
+        'outer: loop {
+            println!("Entry");
+            while condition() {
+                update_condition();
+                if condition() {
+                    println!("foo-1");
+                } else {
+                    continue 'outer; // should not lint here
+                }
+                println!("foo-2");
+
+                update_condition();
+                if condition() {
+                    continue 'outer; // should not lint here
+                } else {
+                    println!("foo-3");
+                }
+                println!("foo-4");
+            }
+        }
+    }
+
+    // both loops have labels
+    fn bar() {
+        'outer: loop {
+            println!("Entry");
+            'inner: while condition() {
+                update_condition();
+                if condition() {
+                    println!("bar-1");
+                } else {
+                    continue 'outer; // should not lint here
+                }
+                println!("bar-2");
+
+                update_condition();
+                if condition() {
+                    println!("bar-3");
+                } else {
+                    continue 'inner; // should lint here
+                }
+                println!("bar-4");
+
+                update_condition();
+                if condition() {
+                    continue; // should lint here
+                } else {
+                    println!("bar-5");
+                }
+                println!("bar-6");
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr
new file mode 100644
index 00000000000..8d6a37df960
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_continue.stderr
@@ -0,0 +1,99 @@
+error: this `else` block is redundant
+  --> $DIR/needless_continue.rs:28:16
+   |
+LL |           } else {
+   |  ________________^
+LL | |             continue;
+LL | |         }
+   | |_________^
+   |
+   = note: `-D clippy::needless-continue` implied by `-D warnings`
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                   if i % 2 == 0 && i % 3 == 0 {
+                       println!("{}", i);
+                       println!("{}", i + 1);
+                       if i % 5 == 0 {
+                           println!("{}", i + 2);
+                       }
+                       let i = 0;
+                       println!("bar {} ", i);
+                       // merged code follows:
+                       println!("bleh");
+                       {
+                           println!("blah");
+                       }
+                       if !(!(i == 2) || !(i == 5)) {
+                           println!("lama");
+                       }
+                       if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
+                           continue;
+                       } else {
+                           println!("Blabber");
+                           println!("Jabber");
+                       }
+                       println!("bleh");
+                   }
+
+error: there is no need for an explicit `else` block for this `if` expression
+  --> $DIR/needless_continue.rs:43:9
+   |
+LL | /         if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
+LL | |             continue;
+LL | |         } else {
+LL | |             println!("Blabber");
+LL | |             println!("Jabber");
+LL | |         }
+   | |_________^
+   |
+   = help: consider dropping the `else` clause
+                   if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
+                       continue;
+                   }
+                   {
+                       println!("Blabber");
+                       println!("Jabber");
+                   }
+
+error: this `else` block is redundant
+  --> $DIR/needless_continue.rs:100:24
+   |
+LL |                   } else {
+   |  ________________________^
+LL | |                     continue 'inner; // should lint here
+LL | |                 }
+   | |_________________^
+   |
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                           if condition() {
+                               println!("bar-3");
+                               // merged code follows:
+                               println!("bar-4");
+                               update_condition();
+                               if condition() {
+                                   continue; // should lint here
+                               } else {
+                                   println!("bar-5");
+                               }
+                               println!("bar-6");
+                           }
+
+error: there is no need for an explicit `else` block for this `if` expression
+  --> $DIR/needless_continue.rs:106:17
+   |
+LL | /                 if condition() {
+LL | |                     continue; // should lint here
+LL | |                 } else {
+LL | |                     println!("bar-5");
+LL | |                 }
+   | |_________________^
+   |
+   = help: consider dropping the `else` clause
+                           if condition() {
+                               continue; // should lint here
+                           }
+                           {
+                               println!("bar-5");
+                           }
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.rs b/src/tools/clippy/tests/ui/needless_doc_main.rs
new file mode 100644
index 00000000000..682d7b3c4ce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_doc_main.rs
@@ -0,0 +1,74 @@
+/// This is a test for needless `fn main()` in doctests.
+///
+/// # Examples
+///
+/// This should lint
+/// ```
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// This should, too.
+///
+/// ```rust
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// This one too.
+///
+/// ```no_run
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+fn bad_doctests() {}
+
+/// # Examples
+///
+/// This shouldn't lint, because the `main` is empty:
+/// ```
+/// fn main(){}
+/// ```
+///
+/// This shouldn't lint either, because there's a `static`:
+/// ```
+/// static ANSWER: i32 = 42;
+///
+/// fn main() {
+///     assert_eq!(42, ANSWER);
+/// }
+/// ```
+///
+/// Neither should this lint because of `extern crate`:
+/// ```
+/// #![feature(test)]
+/// extern crate test;
+/// fn main() {
+///     assert_eq(1u8, test::black_box(1));
+/// }
+/// ```
+///
+/// We should not lint ignored examples:
+///
+/// ```rust,ignore
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// Or even non-rust examples:
+///
+/// ```text
+/// fn main() {
+///     is what starts the program
+/// }
+/// ```
+fn no_false_positives() {}
+
+fn main() {
+    bad_doctests();
+    no_false_positives();
+}
diff --git a/src/tools/clippy/tests/ui/needless_doc_main.stderr b/src/tools/clippy/tests/ui/needless_doc_main.stderr
new file mode 100644
index 00000000000..65d40ee6832
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_doc_main.stderr
@@ -0,0 +1,22 @@
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:7:4
+   |
+LL | /// fn main() {
+   |    ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
+
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:15:4
+   |
+LL | /// fn main() {
+   |    ^^^^^^^^^^^^
+
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:23:4
+   |
+LL | /// fn main() {
+   |    ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
new file mode 100644
index 00000000000..913cd004f19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -0,0 +1,262 @@
+#![warn(clippy::needless_lifetimes)]
+#![allow(dead_code, clippy::needless_pass_by_value)]
+
+fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
+
+fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
+
+// No error; same lifetime on two params.
+fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
+
+// No error; static involved.
+fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
+
+fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
+
+fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+    x
+}
+
+// No error; multiple input refs.
+fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
+    x
+}
+
+// No error; multiple input refs.
+fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
+    x
+}
+
+// No error; static involved.
+fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
+    x
+}
+
+// No error.
+fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
+    Ok(x)
+}
+
+// No error; two input refs.
+fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
+    x.unwrap()
+}
+
+fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+    Ok(x)
+}
+
+// Where-clause, but without lifetimes.
+fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+where
+    T: Copy,
+{
+    Ok(x)
+}
+
+type Ref<'r> = &'r u8;
+
+// No error; same lifetime on two params.
+fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
+
+fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
+where
+    'b: 'a,
+{
+}
+
+struct Lt<'a, I: 'static> {
+    x: &'a I,
+}
+
+// No error; fn bound references `'a`.
+fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+where
+    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
+{
+    unreachable!()
+}
+
+fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+where
+    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
+{
+    unreachable!()
+}
+
+// No error; see below.
+fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
+    f(x);
+}
+
+fn fn_bound_3_cannot_elide() {
+    let x = 42;
+    let p = &x;
+    let mut q = &x;
+    // This will fail if we elide lifetimes of `fn_bound_3`.
+    fn_bound_3(p, |y| q = y);
+}
+
+// No error; multiple input refs.
+fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
+    if cond {
+        x
+    } else {
+        f()
+    }
+}
+
+struct X {
+    x: u8,
+}
+
+impl X {
+    fn self_and_out<'s>(&'s self) -> &'s u8 {
+        &self.x
+    }
+
+    // No error; multiple input refs.
+    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
+        &self.x
+    }
+
+    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
+
+    // No error; same lifetimes on two params.
+    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
+}
+
+struct Foo<'a>(&'a u8);
+
+impl<'a> Foo<'a> {
+    // No error; lifetime `'a` not defined in method.
+    fn self_shared_lifetime(&self, _: &'a u8) {}
+    // No error; bounds exist.
+    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
+}
+
+fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
+    unimplemented!()
+}
+
+fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
+fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
+fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes.
+fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
+    unimplemented!()
+}
+
+trait WithLifetime<'a> {}
+
+type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
+
+// Should not warn because it won't build without the lifetime.
+fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
+    unimplemented!()
+}
+
+// Should warn because there is no lifetime on `Drop`, so this would be
+// unambiguous if we elided the lifetime.
+fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
+    unimplemented!()
+}
+
+type FooAlias<'a> = Foo<'a>;
+
+fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
+fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
+fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes.
+fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
+    unimplemented!()
+}
+
+fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+    unimplemented!()
+}
+
+fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
+    unimplemented!()
+}
+
+fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+    unimplemented!()
+}
+fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
+    unimplemented!()
+}
+
+// Don't warn on these; see issue #292.
+fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
+    unimplemented!()
+}
+
+// See issue #740.
+struct Test {
+    vec: Vec<usize>,
+}
+
+impl Test {
+    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
+        unimplemented!()
+    }
+}
+
+trait LintContext<'a> {}
+
+fn f<'a, T: LintContext<'a>>(_: &T) {}
+
+fn test<'a>(x: &'a [u8]) -> u8 {
+    let y: &'a u8 = &x[5];
+    *y
+}
+
+// Issue #3284: give hint regarding lifetime in return type.
+struct Cow<'a> {
+    x: &'a str,
+}
+fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+    unimplemented!()
+}
+
+// Make sure we still warn on implementations
+mod issue4291 {
+    trait BadTrait {
+        fn needless_lt<'a>(x: &'a u8) {}
+    }
+
+    impl BadTrait for () {
+        fn needless_lt<'a>(_x: &'a u8) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
new file mode 100644
index 00000000000..d3a360ed8b5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -0,0 +1,106 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:4:1
+   |
+LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:6:1
+   |
+LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:16:1
+   |
+LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:45:1
+   |
+LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:50:1
+   |
+LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:62:1
+   |
+LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:86:1
+   |
+LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:120:5
+   |
+LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:129:5
+   |
+LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:148:1
+   |
+LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:178:1
+   |
+LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:184:1
+   |
+LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:203:1
+   |
+LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:211:1
+   |
+LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:247:1
+   |
+LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:254:9
+   |
+LL |         fn needless_lt<'a>(x: &'a u8) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:258:9
+   |
+LL |         fn needless_lt<'a>(_x: &'a u8) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.rs b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
new file mode 100644
index 00000000000..e93a7fe2985
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
@@ -0,0 +1,161 @@
+#![warn(clippy::needless_pass_by_value)]
+#![allow(
+    dead_code,
+    clippy::single_match,
+    clippy::redundant_pattern_matching,
+    clippy::many_single_char_names,
+    clippy::option_option,
+    clippy::redundant_clone
+)]
+
+use std::borrow::Borrow;
+use std::collections::HashSet;
+use std::convert::AsRef;
+use std::mem::MaybeUninit;
+
+// `v` should be warned
+// `w`, `x` and `y` are allowed (moved or mutated)
+fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
+    assert_eq!(v.len(), 42);
+
+    consume(w);
+
+    x.push(T::default());
+
+    y
+}
+
+fn consume<T>(_: T) {}
+
+struct Wrapper(String);
+
+fn bar(x: String, y: Wrapper) {
+    assert_eq!(x.len(), 42);
+    assert_eq!(y.0.len(), 42);
+}
+
+// V implements `Borrow<V>`, but should be warned correctly
+fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
+    println!("{}", t.borrow());
+    println!("{}", u.as_ref());
+    consume(&v);
+}
+
+// ok
+fn test_fn<F: Fn(i32) -> i32>(f: F) {
+    f(1);
+}
+
+// x should be warned, but y is ok
+fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
+    match x {
+        Some(Some(_)) => 1, // not moved
+        _ => 0,
+    };
+
+    match y {
+        Some(Some(s)) => consume(s), // moved
+        _ => (),
+    };
+}
+
+// x and y should be warned, but z is ok
+fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
+    let Wrapper(s) = z; // moved
+    let Wrapper(ref t) = y; // not moved
+    let Wrapper(_) = y; // still not moved
+
+    assert_eq!(x.0.len(), s.len());
+    println!("{}", t);
+}
+
+trait Foo {}
+
+// `S: Serialize` is allowed to be passed by value, since a caller can pass `&S` instead
+trait Serialize {}
+impl<'a, T> Serialize for &'a T where T: Serialize {}
+impl Serialize for i32 {}
+
+fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {}
+
+fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+    s.capacity();
+    let _ = t.clone();
+    u.capacity();
+    let _ = v.clone();
+}
+
+struct S<T, U>(T, U);
+
+impl<T: Serialize, U> S<T, U> {
+    fn foo(
+        self,
+        // taking `self` by value is always allowed
+        s: String,
+        t: String,
+    ) -> usize {
+        s.len() + t.capacity()
+    }
+
+    fn bar(_t: T, // Ok, since `&T: Serialize` too
+    ) {
+    }
+
+    fn baz(&self, _u: U, _s: Self) {}
+}
+
+trait FalsePositive {
+    fn visit_str(s: &str);
+    fn visit_string(s: String) {
+        Self::visit_str(&s);
+    }
+}
+
+// shouldn't warn on extern funcs
+extern "C" fn ext(x: MaybeUninit<usize>) -> usize {
+    unsafe { x.assume_init() }
+}
+
+// whitelist RangeArgument
+fn range<T: ::std::ops::RangeBounds<usize>>(range: T) {
+    let _ = range.start_bound();
+}
+
+struct CopyWrapper(u32);
+
+fn bar_copy(x: u32, y: CopyWrapper) {
+    assert_eq!(x, 42);
+    assert_eq!(y.0, 42);
+}
+
+// x and y should be warned, but z is ok
+fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+    let CopyWrapper(s) = z; // moved
+    let CopyWrapper(ref t) = y; // not moved
+    let CopyWrapper(_) = y; // still not moved
+
+    assert_eq!(x.0, s);
+    println!("{}", t);
+}
+
+// The following 3 lines should not cause an ICE. See #2831
+trait Bar<'a, A> {}
+impl<'b, T> Bar<'b, T> for T {}
+fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {}
+
+// Also this should not cause an ICE. See #2831
+trait Club<'a, A> {}
+impl<T> Club<'static, T> for T {}
+fn more_fun(_item: impl Club<'static, i32>) {}
+
+fn is_sync<T>(_: T)
+where
+    T: Sync,
+{
+}
+
+fn main() {
+    // This should not cause an ICE either
+    // https://github.com/rust-lang/rust-clippy/issues/3144
+    is_sync(HashSet::<usize>::new());
+}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
new file mode 100644
index 00000000000..9aa783bf904
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
@@ -0,0 +1,178 @@
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:18:23
+   |
+LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
+   |                       ^^^^^^ help: consider changing the type to: `&[T]`
+   |
+   = note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:32:11
+   |
+LL | fn bar(x: String, y: Wrapper) {
+   |           ^^^^^^ help: consider changing the type to: `&str`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:32:22
+   |
+LL | fn bar(x: String, y: Wrapper) {
+   |                      ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:38:71
+   |
+LL | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
+   |                                                                       ^ help: consider taking a reference instead: `&V`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:50:18
+   |
+LL | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
+   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option<Option<String>>`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:63:24
+   |
+LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
+   |                        ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:63:36
+   |
+LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
+   |                                    ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:79:49
+   |
+LL | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {}
+   |                                                 ^ help: consider taking a reference instead: `&T`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:81:18
+   |
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+   |                  ^^^^^^ help: consider taking a reference instead: `&String`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:81:29
+   |
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+   |                             ^^^^^^
+   |
+help: consider changing the type to
+   |
+LL | fn issue_2114(s: String, t: &str, u: Vec<i32>, v: Vec<i32>) {
+   |                             ^^^^
+help: change `t.clone()` to
+   |
+LL |     let _ = t.to_string();
+   |             ^^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:81:40
+   |
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+   |                                        ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:81:53
+   |
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+   |                                                     ^^^^^^^^
+   |
+help: consider changing the type to
+   |
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: &[i32]) {
+   |                                                     ^^^^^^
+help: change `v.clone()` to
+   |
+LL |     let _ = v.to_owned();
+   |             ^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:94:12
+   |
+LL |         s: String,
+   |            ^^^^^^ help: consider changing the type to: `&str`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:95:12
+   |
+LL |         t: String,
+   |            ^^^^^^ help: consider taking a reference instead: `&String`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:104:23
+   |
+LL |     fn baz(&self, _u: U, _s: Self) {}
+   |                       ^ help: consider taking a reference instead: `&U`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:104:30
+   |
+LL |     fn baz(&self, _u: U, _s: Self) {}
+   |                              ^^^^ help: consider taking a reference instead: `&Self`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:126:24
+   |
+LL | fn bar_copy(x: u32, y: CopyWrapper) {
+   |                        ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
+help: consider marking this type as `Copy`
+  --> $DIR/needless_pass_by_value.rs:124:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:132:29
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
+help: consider marking this type as `Copy`
+  --> $DIR/needless_pass_by_value.rs:124:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:132:45
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
+help: consider marking this type as `Copy`
+  --> $DIR/needless_pass_by_value.rs:124:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:132:61
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                                                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
+help: consider marking this type as `Copy`
+  --> $DIR/needless_pass_by_value.rs:124:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:144:40
+   |
+LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {}
+   |                                        ^ help: consider taking a reference instead: `&S`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:149:20
+   |
+LL | fn more_fun(_item: impl Club<'static, i32>) {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>`
+
+error: aborting due to 22 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs b/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs
new file mode 100644
index 00000000000..78a0e92d179
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs
@@ -0,0 +1,21 @@
+#![crate_type = "proc-macro"]
+#![warn(clippy::needless_pass_by_value)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Foo)]
+pub fn foo(_input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+#[proc_macro]
+pub fn bar(_input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+#[proc_macro_attribute]
+pub fn baz(_args: TokenStream, _input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs
new file mode 100644
index 00000000000..3fce34367ae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_range_loop.rs
@@ -0,0 +1,95 @@
+#![warn(clippy::needless_range_loop)]
+
+static STATIC: [usize; 4] = [0, 1, 8, 16];
+const CONST: [usize; 4] = [0, 1, 8, 16];
+const MAX_LEN: usize = 42;
+
+fn main() {
+    let mut vec = vec![1, 2, 3, 4];
+    let vec2 = vec![1, 2, 3, 4];
+    for i in 0..vec.len() {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..vec.len() {
+        let i = 42; // make a different `i`
+        println!("{}", vec[i]); // ok, not the `i` of the for-loop
+    }
+
+    for i in 0..vec.len() {
+        let _ = vec[i];
+    }
+
+    // ICE #746
+    for j in 0..4 {
+        println!("{:?}", STATIC[j]);
+    }
+
+    for j in 0..4 {
+        println!("{:?}", CONST[j]);
+    }
+
+    for i in 0..vec.len() {
+        println!("{} {}", vec[i], i);
+    }
+    for i in 0..vec.len() {
+        // not an error, indexing more than one variable
+        println!("{} {}", vec[i], vec2[i]);
+    }
+
+    for i in 0..vec.len() {
+        println!("{}", vec2[i]);
+    }
+
+    for i in 5..vec.len() {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..MAX_LEN {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..=MAX_LEN {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..10 {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..=10 {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..vec.len() {
+        println!("{} {}", vec[i], i);
+    }
+
+    for i in 5..10 {
+        println!("{} {}", vec[i], i);
+    }
+
+    // #2542
+    for i in 0..vec.len() {
+        vec[i] = Some(1).unwrap_or_else(|| panic!("error on {}", i));
+    }
+
+    // #3788
+    let test = Test {
+        inner: vec![1, 2, 3, 4],
+    };
+    for i in 0..2 {
+        println!("{}", test[i]);
+    }
+}
+
+struct Test {
+    inner: Vec<usize>,
+}
+
+impl std::ops::Index<usize> for Test {
+    type Output = usize;
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.inner[index]
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
new file mode 100644
index 00000000000..c50c4931fb4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -0,0 +1,157 @@
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:10:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-range-loop` implied by `-D warnings`
+help: consider using an iterator
+   |
+LL |     for <item> in &vec {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:19:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &vec {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `j` is only used to index `STATIC`.
+  --> $DIR/needless_range_loop.rs:24:14
+   |
+LL |     for j in 0..4 {
+   |              ^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &STATIC {
+   |         ^^^^^^    ^^^^^^^
+
+error: the loop variable `j` is only used to index `CONST`.
+  --> $DIR/needless_range_loop.rs:28:14
+   |
+LL |     for j in 0..4 {
+   |              ^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &CONST {
+   |         ^^^^^^    ^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:32:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate() {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec2`.
+  --> $DIR/needless_range_loop.rs:40:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec2.iter().take(vec.len()) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:44:14
+   |
+LL |     for i in 5..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:48:14
+   |
+LL |     for i in 0..MAX_LEN {
+   |              ^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(MAX_LEN) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:52:14
+   |
+LL |     for i in 0..=MAX_LEN {
+   |              ^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(MAX_LEN + 1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:56:14
+   |
+LL |     for i in 5..10 {
+   |              ^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(10).skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:60:14
+   |
+LL |     for i in 5..=10 {
+   |              ^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(10 + 1).skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:64:14
+   |
+LL |     for i in 5..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate().skip(5) {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:68:14
+   |
+LL |     for i in 5..10 {
+   |              ^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:73:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter_mut().enumerate() {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.rs b/src/tools/clippy/tests/ui/needless_range_loop2.rs
new file mode 100644
index 00000000000..2ed1b09bece
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_range_loop2.rs
@@ -0,0 +1,85 @@
+#![warn(clippy::needless_range_loop)]
+
+fn calc_idx(i: usize) -> usize {
+    (i + i + 20) % 4
+}
+
+fn main() {
+    let ns = vec![2, 3, 5, 7];
+
+    for i in 3..10 {
+        println!("{}", ns[i]);
+    }
+
+    for i in 3..10 {
+        println!("{}", ns[i % 4]);
+    }
+
+    for i in 3..10 {
+        println!("{}", ns[i % ns.len()]);
+    }
+
+    for i in 3..10 {
+        println!("{}", ns[calc_idx(i)]);
+    }
+
+    for i in 3..10 {
+        println!("{}", ns[calc_idx(i) % 4]);
+    }
+
+    let mut ms = vec![1, 2, 3, 4, 5, 6];
+    for i in 0..ms.len() {
+        ms[i] *= 2;
+    }
+    assert_eq!(ms, vec![2, 4, 6, 8, 10, 12]);
+
+    let mut ms = vec![1, 2, 3, 4, 5, 6];
+    for i in 0..ms.len() {
+        let x = &mut ms[i];
+        *x *= 2;
+    }
+    assert_eq!(ms, vec![2, 4, 6, 8, 10, 12]);
+
+    let g = vec![1, 2, 3, 4, 5, 6];
+    let glen = g.len();
+    for i in 0..glen {
+        let x: u32 = g[i + 1..].iter().sum();
+        println!("{}", g[i] + x);
+    }
+    assert_eq!(g, vec![20, 18, 15, 11, 6, 0]);
+
+    let mut g = vec![1, 2, 3, 4, 5, 6];
+    let glen = g.len();
+    for i in 0..glen {
+        g[i] = g[i + 1..].iter().sum();
+    }
+    assert_eq!(g, vec![20, 18, 15, 11, 6, 0]);
+
+    let x = 5;
+    let mut vec = vec![0; 9];
+
+    for i in x..x + 4 {
+        vec[i] += 1;
+    }
+
+    let x = 5;
+    let mut vec = vec![0; 10];
+
+    for i in x..=x + 4 {
+        vec[i] += 1;
+    }
+
+    let arr = [1, 2, 3];
+
+    for i in 0..3 {
+        println!("{}", arr[i]);
+    }
+
+    for i in 0..2 {
+        println!("{}", arr[i]);
+    }
+
+    for i in 1..3 {
+        println!("{}", arr[i]);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.stderr b/src/tools/clippy/tests/ui/needless_range_loop2.stderr
new file mode 100644
index 00000000000..c54ab5ec980
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_range_loop2.stderr
@@ -0,0 +1,91 @@
+error: the loop variable `i` is only used to index `ns`.
+  --> $DIR/needless_range_loop2.rs:10:14
+   |
+LL |     for i in 3..10 {
+   |              ^^^^^
+   |
+   = note: `-D clippy::needless-range-loop` implied by `-D warnings`
+help: consider using an iterator
+   |
+LL |     for <item> in ns.iter().take(10).skip(3) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `ms`.
+  --> $DIR/needless_range_loop2.rs:31:14
+   |
+LL |     for i in 0..ms.len() {
+   |              ^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &mut ms {
+   |         ^^^^^^    ^^^^^^^
+
+error: the loop variable `i` is only used to index `ms`.
+  --> $DIR/needless_range_loop2.rs:37:14
+   |
+LL |     for i in 0..ms.len() {
+   |              ^^^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &mut ms {
+   |         ^^^^^^    ^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop2.rs:61:14
+   |
+LL |     for i in x..x + 4 {
+   |              ^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter_mut().skip(x).take(4) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop2.rs:68:14
+   |
+LL |     for i in x..=x + 4 {
+   |              ^^^^^^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter_mut().skip(x).take(4 + 1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop2.rs:74:14
+   |
+LL |     for i in 0..3 {
+   |              ^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in &arr {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop2.rs:78:14
+   |
+LL |     for i in 0..2 {
+   |              ^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in arr.iter().take(2) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop2.rs:82:14
+   |
+LL |     for i in 1..3 {
+   |              ^^^^
+   |
+help: consider using an iterator
+   |
+LL |     for <item> in arr.iter().skip(1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
new file mode 100644
index 00000000000..ad20e238107
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -0,0 +1,78 @@
+// run-rustfix
+
+#![allow(unused, clippy::needless_bool)]
+#![allow(clippy::if_same_then_else, clippy::single_match)]
+#![warn(clippy::needless_return)]
+
+macro_rules! the_answer {
+    () => {
+        42
+    };
+}
+
+fn test_end_of_fn() -> bool {
+    if true {
+        // no error!
+        return true;
+    }
+    true
+}
+
+fn test_no_semicolon() -> bool {
+    true
+}
+
+fn test_if_block() -> bool {
+    if true {
+        true
+    } else {
+        false
+    }
+}
+
+fn test_match(x: bool) -> bool {
+    match x {
+        true => false,
+        false => {
+            true
+        },
+    }
+}
+
+fn test_closure() {
+    let _ = || {
+        true
+    };
+    let _ = || true;
+}
+
+fn test_macro_call() -> i32 {
+    return the_answer!();
+}
+
+fn test_void_fun() {
+    
+}
+
+fn test_void_if_fun(b: bool) {
+    if b {
+        
+    } else {
+        
+    }
+}
+
+fn test_void_match(x: u32) {
+    match x {
+        0 => (),
+        _ => {},
+    }
+}
+
+fn main() {
+    let _ = test_end_of_fn();
+    let _ = test_no_semicolon();
+    let _ = test_if_block();
+    let _ = test_match(true);
+    test_closure();
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
new file mode 100644
index 00000000000..af0cdfb207f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -0,0 +1,78 @@
+// run-rustfix
+
+#![allow(unused, clippy::needless_bool)]
+#![allow(clippy::if_same_then_else, clippy::single_match)]
+#![warn(clippy::needless_return)]
+
+macro_rules! the_answer {
+    () => {
+        42
+    };
+}
+
+fn test_end_of_fn() -> bool {
+    if true {
+        // no error!
+        return true;
+    }
+    return true;
+}
+
+fn test_no_semicolon() -> bool {
+    return true;
+}
+
+fn test_if_block() -> bool {
+    if true {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+fn test_match(x: bool) -> bool {
+    match x {
+        true => return false,
+        false => {
+            return true;
+        },
+    }
+}
+
+fn test_closure() {
+    let _ = || {
+        return true;
+    };
+    let _ = || return true;
+}
+
+fn test_macro_call() -> i32 {
+    return the_answer!();
+}
+
+fn test_void_fun() {
+    return;
+}
+
+fn test_void_if_fun(b: bool) {
+    if b {
+        return;
+    } else {
+        return;
+    }
+}
+
+fn test_void_match(x: u32) {
+    match x {
+        0 => (),
+        _ => return,
+    }
+}
+
+fn main() {
+    let _ = test_end_of_fn();
+    let _ = test_no_semicolon();
+    let _ = test_if_block();
+    let _ = test_match(true);
+    test_closure();
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
new file mode 100644
index 00000000000..c34eecbcbb6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -0,0 +1,76 @@
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:18:5
+   |
+LL |     return true;
+   |     ^^^^^^^^^^^^ help: remove `return`: `true`
+   |
+   = note: `-D clippy::needless-return` implied by `-D warnings`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:22:5
+   |
+LL |     return true;
+   |     ^^^^^^^^^^^^ help: remove `return`: `true`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:27:9
+   |
+LL |         return true;
+   |         ^^^^^^^^^^^^ help: remove `return`: `true`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:29:9
+   |
+LL |         return false;
+   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:35:17
+   |
+LL |         true => return false,
+   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:37:13
+   |
+LL |             return true;
+   |             ^^^^^^^^^^^^ help: remove `return`: `true`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:44:9
+   |
+LL |         return true;
+   |         ^^^^^^^^^^^^ help: remove `return`: `true`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:46:16
+   |
+LL |     let _ = || return true;
+   |                ^^^^^^^^^^^ help: remove `return`: `true`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:54:5
+   |
+LL |     return;
+   |     ^^^^^^^ help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:59:9
+   |
+LL |         return;
+   |         ^^^^^^^ help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:61:9
+   |
+LL |         return;
+   |         ^^^^^^^ help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:68:14
+   |
+LL |         _ => return,
+   |              ^^^^^^ help: replace `return` with an empty block: `{}`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_update.rs b/src/tools/clippy/tests/ui/needless_update.rs
new file mode 100644
index 00000000000..bfa005a19f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_update.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::needless_update)]
+#![allow(clippy::no_effect)]
+
+struct S {
+    pub a: i32,
+    pub b: i32,
+}
+
+fn main() {
+    let base = S { a: 0, b: 0 };
+    S { ..base }; // no error
+    S { a: 1, ..base }; // no error
+    S { a: 1, b: 1, ..base };
+}
diff --git a/src/tools/clippy/tests/ui/needless_update.stderr b/src/tools/clippy/tests/ui/needless_update.stderr
new file mode 100644
index 00000000000..133c834880d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_update.stderr
@@ -0,0 +1,10 @@
+error: struct update has no effect, all the fields in the struct have already been specified
+  --> $DIR/needless_update.rs:13:23
+   |
+LL |     S { a: 1, b: 1, ..base };
+   |                       ^^^^
+   |
+   = note: `-D clippy::needless-update` implied by `-D warnings`
+
+error: aborting due to previous error
+
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
new file mode 100644
index 00000000000..856a430ba2b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs
@@ -0,0 +1,61 @@
+//! This test case utilizes `f64` an easy example for `PartialOrd` only types
+//! but the lint itself actually validates any expression where the left
+//! operand implements `PartialOrd` but not `Ord`.
+
+use std::cmp::Ordering;
+
+#[warn(clippy::neg_cmp_op_on_partial_ord)]
+fn main() {
+    let a_value = 1.0;
+    let another_value = 7.0;
+
+    // --- Bad ---
+
+    // Not Less but potentially Greater, Equal or Uncomparable.
+    let _not_less = !(a_value < another_value);
+
+    // Not Less or Equal but potentially Greater or Uncomparable.
+    let _not_less_or_equal = !(a_value <= another_value);
+
+    // Not Greater but potentially Less, Equal or Uncomparable.
+    let _not_greater = !(a_value > another_value);
+
+    // Not Greater or Equal but potentially Less or Uncomparable.
+    let _not_greater_or_equal = !(a_value >= another_value);
+
+    // --- Good ---
+
+    let _not_less = match a_value.partial_cmp(&another_value) {
+        None | Some(Ordering::Greater) | Some(Ordering::Equal) => true,
+        _ => false,
+    };
+    let _not_less_or_equal = match a_value.partial_cmp(&another_value) {
+        None | Some(Ordering::Greater) => true,
+        _ => false,
+    };
+    let _not_greater = match a_value.partial_cmp(&another_value) {
+        None | Some(Ordering::Less) | Some(Ordering::Equal) => true,
+        _ => false,
+    };
+    let _not_greater_or_equal = match a_value.partial_cmp(&another_value) {
+        None | Some(Ordering::Less) => true,
+        _ => false,
+    };
+
+    // --- Should not trigger ---
+
+    let _ = a_value < another_value;
+    let _ = a_value <= another_value;
+    let _ = a_value > another_value;
+    let _ = a_value >= another_value;
+
+    // --- regression tests ---
+
+    // Issue 2856: False positive on assert!()
+    //
+    // The macro always negates the result of the given comparison in its
+    // internal check which automatically triggered the lint. As it's an
+    // external macro there was no chance to do anything about it which led
+    // to a whitelisting of all external macros.
+    assert!(a_value < another_value);
+}
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
new file mode 100644
index 00000000000..d05fd34ce33
--- /dev/null
+++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
@@ -0,0 +1,28 @@
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+LL |     let _not_greater_or_equal = !(a_value >= another_value);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs
new file mode 100644
index 00000000000..d4a20ce9db1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/neg_multiply.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::neg_multiply)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+use std::ops::Mul;
+
+struct X;
+
+impl Mul<isize> for X {
+    type Output = X;
+
+    fn mul(self, _r: isize) -> Self {
+        self
+    }
+}
+
+impl Mul<X> for isize {
+    type Output = X;
+
+    fn mul(self, _r: X) -> X {
+        X
+    }
+}
+
+fn main() {
+    let x = 0;
+
+    x * -1;
+
+    -1 * x;
+
+    -1 * -1; // should be ok
+
+    X * -1; // should be ok
+    -1 * X; // should also be ok
+}
diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr
new file mode 100644
index 00000000000..f08bbd6a12c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/neg_multiply.stderr
@@ -0,0 +1,16 @@
+error: Negation by multiplying with `-1`
+  --> $DIR/neg_multiply.rs:27:5
+   |
+LL |     x * -1;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::neg-multiply` implied by `-D warnings`
+
+error: Negation by multiplying with `-1`
+  --> $DIR/neg_multiply.rs:29:5
+   |
+LL |     -1 * x;
+   |     ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
new file mode 100644
index 00000000000..cbc4ca39161
--- /dev/null
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -0,0 +1,204 @@
+#![allow(
+    clippy::single_match,
+    unused_assignments,
+    unused_variables,
+    clippy::while_immutable_condition
+)]
+
+fn test1() {
+    let mut x = 0;
+    loop {
+        // clippy::never_loop
+        x += 1;
+        if x == 1 {
+            return;
+        }
+        break;
+    }
+}
+
+fn test2() {
+    let mut x = 0;
+    loop {
+        x += 1;
+        if x == 1 {
+            break;
+        }
+    }
+}
+
+fn test3() {
+    let mut x = 0;
+    loop {
+        // never loops
+        x += 1;
+        break;
+    }
+}
+
+fn test4() {
+    let mut x = 1;
+    loop {
+        x += 1;
+        match x {
+            5 => return,
+            _ => (),
+        }
+    }
+}
+
+fn test5() {
+    let i = 0;
+    loop {
+        // never loops
+        while i == 0 {
+            // never loops
+            break;
+        }
+        return;
+    }
+}
+
+fn test6() {
+    let mut x = 0;
+    'outer: loop {
+        x += 1;
+        loop {
+            // never loops
+            if x == 5 {
+                break;
+            }
+            continue 'outer;
+        }
+        return;
+    }
+}
+
+fn test7() {
+    let mut x = 0;
+    loop {
+        x += 1;
+        match x {
+            1 => continue,
+            _ => (),
+        }
+        return;
+    }
+}
+
+fn test8() {
+    let mut x = 0;
+    loop {
+        x += 1;
+        match x {
+            5 => return,
+            _ => continue,
+        }
+    }
+}
+
+fn test9() {
+    let x = Some(1);
+    while let Some(y) = x {
+        // never loops
+        return;
+    }
+}
+
+fn test10() {
+    for x in 0..10 {
+        // never loops
+        match x {
+            1 => break,
+            _ => return,
+        }
+    }
+}
+
+fn test11<F: FnMut() -> i32>(mut f: F) {
+    loop {
+        return match f() {
+            1 => continue,
+            _ => (),
+        };
+    }
+}
+
+pub fn test12(a: bool, b: bool) {
+    'label: loop {
+        loop {
+            if a {
+                continue 'label;
+            }
+            if b {
+                break;
+            }
+        }
+        break;
+    }
+}
+
+pub fn test13() {
+    let mut a = true;
+    loop {
+        // infinite loop
+        while a {
+            if true {
+                a = false;
+                continue;
+            }
+            return;
+        }
+    }
+}
+
+pub fn test14() {
+    let mut a = true;
+    'outer: while a {
+        // never loops
+        while a {
+            if a {
+                a = false;
+                continue;
+            }
+        }
+        break 'outer;
+    }
+}
+
+// Issue #1991: the outter loop should not warn.
+pub fn test15() {
+    'label: loop {
+        while false {
+            break 'label;
+        }
+    }
+}
+
+// Issue #4058: `continue` in `break` expression
+pub fn test16() {
+    let mut n = 1;
+    loop {
+        break if n != 5 {
+            n += 1;
+            continue;
+        };
+    }
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+    test4();
+    test5();
+    test6();
+    test7();
+    test8();
+    test9();
+    test10();
+    test11(|| 0);
+    test12(true, false);
+    test13();
+    test14();
+}
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
new file mode 100644
index 00000000000..c00b4c78cf2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -0,0 +1,100 @@
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:10:5
+   |
+LL | /     loop {
+LL | |         // clippy::never_loop
+LL | |         x += 1;
+LL | |         if x == 1 {
+...  |
+LL | |         break;
+LL | |     }
+   | |_____^
+   |
+   = note: `#[deny(clippy::never_loop)]` on by default
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:32:5
+   |
+LL | /     loop {
+LL | |         // never loops
+LL | |         x += 1;
+LL | |         break;
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:52:5
+   |
+LL | /     loop {
+LL | |         // never loops
+LL | |         while i == 0 {
+LL | |             // never loops
+...  |
+LL | |         return;
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:54:9
+   |
+LL | /         while i == 0 {
+LL | |             // never loops
+LL | |             break;
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:66:9
+   |
+LL | /         loop {
+LL | |             // never loops
+LL | |             if x == 5 {
+LL | |                 break;
+LL | |             }
+LL | |             continue 'outer;
+LL | |         }
+   | |_________^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:102:5
+   |
+LL | /     while let Some(y) = x {
+LL | |         // never loops
+LL | |         return;
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:109:5
+   |
+LL | /     for x in 0..10 {
+LL | |         // never loops
+LL | |         match x {
+LL | |             1 => break,
+LL | |             _ => return,
+LL | |         }
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:157:5
+   |
+LL | /     'outer: while a {
+LL | |         // never loops
+LL | |         while a {
+LL | |             if a {
+...  |
+LL | |         break 'outer;
+LL | |     }
+   | |_____^
+
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:172:9
+   |
+LL | /         while false {
+LL | |             break 'label;
+LL | |         }
+   | |_________^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs
new file mode 100644
index 00000000000..2c2d1e27589
--- /dev/null
+++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs
@@ -0,0 +1,212 @@
+#![warn(clippy::new_ret_no_self)]
+#![allow(dead_code)]
+
+fn main() {}
+
+trait R {
+    type Item;
+}
+
+trait Q {
+    type Item;
+    type Item2;
+}
+
+struct S;
+
+impl R for S {
+    type Item = Self;
+}
+
+impl S {
+    // should not trigger the lint
+    pub fn new() -> impl R<Item = Self> {
+        S
+    }
+}
+
+struct S2;
+
+impl R for S2 {
+    type Item = Self;
+}
+
+impl S2 {
+    // should not trigger the lint
+    pub fn new(_: String) -> impl R<Item = Self> {
+        S2
+    }
+}
+
+struct S3;
+
+impl R for S3 {
+    type Item = u32;
+}
+
+impl S3 {
+    // should trigger the lint
+    pub fn new(_: String) -> impl R<Item = u32> {
+        S3
+    }
+}
+
+struct S4;
+
+impl Q for S4 {
+    type Item = u32;
+    type Item2 = Self;
+}
+
+impl S4 {
+    // should not trigger the lint
+    pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
+        S4
+    }
+}
+
+struct T;
+
+impl T {
+    // should not trigger lint
+    pub fn new() -> Self {
+        unimplemented!();
+    }
+}
+
+struct U;
+
+impl U {
+    // should trigger lint
+    pub fn new() -> u32 {
+        unimplemented!();
+    }
+}
+
+struct V;
+
+impl V {
+    // should trigger lint
+    pub fn new(_: String) -> u32 {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk;
+
+impl TupleReturnerOk {
+    // should not trigger lint
+    pub fn new() -> (Self, u32) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk2;
+
+impl TupleReturnerOk2 {
+    // should not trigger lint (it doesn't matter which element in the tuple is Self)
+    pub fn new() -> (u32, Self) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk3;
+
+impl TupleReturnerOk3 {
+    // should not trigger lint (tuple can contain multiple Self)
+    pub fn new() -> (Self, Self) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerBad;
+
+impl TupleReturnerBad {
+    // should trigger lint
+    pub fn new() -> (u32, u32) {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerOk;
+
+impl MutPointerReturnerOk {
+    // should not trigger lint
+    pub fn new() -> *mut Self {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerOk2;
+
+impl MutPointerReturnerOk2 {
+    // should not trigger lint
+    pub fn new() -> *const Self {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerBad;
+
+impl MutPointerReturnerBad {
+    // should trigger lint
+    pub fn new() -> *mut V {
+        unimplemented!();
+    }
+}
+
+struct GenericReturnerOk;
+
+impl GenericReturnerOk {
+    // should not trigger lint
+    pub fn new() -> Option<Self> {
+        unimplemented!();
+    }
+}
+
+struct GenericReturnerBad;
+
+impl GenericReturnerBad {
+    // should trigger lint
+    pub fn new() -> Option<u32> {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk;
+
+impl NestedReturnerOk {
+    // should not trigger lint
+    pub fn new() -> (Option<Self>, u32) {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk2;
+
+impl NestedReturnerOk2 {
+    // should not trigger lint
+    pub fn new() -> ((Self, u32), u32) {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk3;
+
+impl NestedReturnerOk3 {
+    // should not trigger lint
+    pub fn new() -> Option<(Self, u32)> {
+        unimplemented!();
+    }
+}
+
+struct WithLifetime<'a> {
+    cat: &'a str,
+}
+
+impl<'a> WithLifetime<'a> {
+    // should not trigger the lint, because the lifetimes are different
+    pub fn new<'b: 'a>(s: &'b str) -> WithLifetime<'b> {
+        unimplemented!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr
new file mode 100644
index 00000000000..dd5a24bcbe7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr
@@ -0,0 +1,52 @@
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:49:5
+   |
+LL | /     pub fn new(_: String) -> impl R<Item = u32> {
+LL | |         S3
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:81:5
+   |
+LL | /     pub fn new() -> u32 {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:90:5
+   |
+LL | /     pub fn new(_: String) -> u32 {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:126:5
+   |
+LL | /     pub fn new() -> (u32, u32) {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:153:5
+   |
+LL | /     pub fn new() -> *mut V {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:171:5
+   |
+LL | /     pub fn new() -> Option<u32> {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs
new file mode 100644
index 00000000000..781ea7bb152
--- /dev/null
+++ b/src/tools/clippy/tests/ui/new_without_default.rs
@@ -0,0 +1,151 @@
+#![feature(const_fn)]
+#![allow(dead_code, clippy::missing_safety_doc)]
+#![warn(clippy::new_without_default)]
+
+pub struct Foo;
+
+impl Foo {
+    pub fn new() -> Foo {
+        Foo
+    }
+}
+
+pub struct Bar;
+
+impl Bar {
+    pub fn new() -> Self {
+        Bar
+    }
+}
+
+pub struct Ok;
+
+impl Ok {
+    pub fn new() -> Self {
+        Ok
+    }
+}
+
+impl Default for Ok {
+    fn default() -> Self {
+        Ok
+    }
+}
+
+pub struct Params;
+
+impl Params {
+    pub fn new(_: u32) -> Self {
+        Params
+    }
+}
+
+pub struct GenericsOk<T> {
+    bar: T,
+}
+
+impl<U> Default for GenericsOk<U> {
+    fn default() -> Self {
+        unimplemented!();
+    }
+}
+
+impl<'c, V> GenericsOk<V> {
+    pub fn new() -> GenericsOk<V> {
+        unimplemented!()
+    }
+}
+
+pub struct LtOk<'a> {
+    foo: &'a bool,
+}
+
+impl<'b> Default for LtOk<'b> {
+    fn default() -> Self {
+        unimplemented!();
+    }
+}
+
+impl<'c> LtOk<'c> {
+    pub fn new() -> LtOk<'c> {
+        unimplemented!()
+    }
+}
+
+pub struct LtKo<'a> {
+    foo: &'a bool,
+}
+
+impl<'c> LtKo<'c> {
+    pub fn new() -> LtKo<'c> {
+        unimplemented!()
+    }
+    // FIXME: that suggestion is missing lifetimes
+}
+
+struct Private;
+
+impl Private {
+    fn new() -> Private {
+        unimplemented!()
+    } // We don't lint private items
+}
+
+struct Const;
+
+impl Const {
+    pub const fn new() -> Const {
+        Const
+    } // const fns can't be implemented via Default
+}
+
+pub struct IgnoreGenericNew;
+
+impl IgnoreGenericNew {
+    pub fn new<T>() -> Self {
+        IgnoreGenericNew
+    } // the derived Default does not make sense here as the result depends on T
+}
+
+pub trait TraitWithNew: Sized {
+    fn new() -> Self {
+        panic!()
+    }
+}
+
+pub struct IgnoreUnsafeNew;
+
+impl IgnoreUnsafeNew {
+    pub unsafe fn new() -> Self {
+        IgnoreUnsafeNew
+    }
+}
+
+#[derive(Default)]
+pub struct OptionRefWrapper<'a, T>(Option<&'a T>);
+
+impl<'a, T> OptionRefWrapper<'a, T> {
+    pub fn new() -> Self {
+        OptionRefWrapper(None)
+    }
+}
+
+pub struct Allow(Foo);
+
+impl Allow {
+    #[allow(clippy::new_without_default)]
+    pub fn new() -> Self {
+        unimplemented!()
+    }
+}
+
+pub struct AllowDerive;
+
+impl AllowDerive {
+    #[allow(clippy::new_without_default)]
+    pub fn new() -> Self {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr
new file mode 100644
index 00000000000..5e485d40663
--- /dev/null
+++ b/src/tools/clippy/tests/ui/new_without_default.stderr
@@ -0,0 +1,46 @@
+error: you should consider deriving a `Default` implementation for `Foo`
+  --> $DIR/new_without_default.rs:8:5
+   |
+LL | /     pub fn new() -> Foo {
+LL | |         Foo
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::new-without-default` implied by `-D warnings`
+help: try this
+   |
+LL | #[derive(Default)]
+   |
+
+error: you should consider deriving a `Default` implementation for `Bar`
+  --> $DIR/new_without_default.rs:16:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |         Bar
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL | #[derive(Default)]
+   |
+
+error: you should consider adding a `Default` implementation for `LtKo<'c>`
+  --> $DIR/new_without_default.rs:80:5
+   |
+LL | /     pub fn new() -> LtKo<'c> {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL | impl Default for LtKo<'c> {
+LL |     fn default() -> Self {
+LL |         Self::new()
+LL |     }
+LL | }
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
new file mode 100644
index 00000000000..8fbfcb79860
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -0,0 +1,102 @@
+#![feature(box_syntax)]
+#![warn(clippy::no_effect)]
+#![allow(dead_code)]
+#![allow(path_statements)]
+#![allow(clippy::deref_addrof)]
+#![allow(clippy::redundant_field_names)]
+#![feature(untagged_unions)]
+
+struct Unit;
+struct Tuple(i32);
+struct Struct {
+    field: i32,
+}
+enum Enum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+struct DropUnit;
+impl Drop for DropUnit {
+    fn drop(&mut self) {}
+}
+struct DropStruct {
+    field: i32,
+}
+impl Drop for DropStruct {
+    fn drop(&mut self) {}
+}
+struct DropTuple(i32);
+impl Drop for DropTuple {
+    fn drop(&mut self) {}
+}
+enum DropEnum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+impl Drop for DropEnum {
+    fn drop(&mut self) {}
+}
+struct FooString {
+    s: String,
+}
+union Union {
+    a: u8,
+    b: f64,
+}
+
+fn get_number() -> i32 {
+    0
+}
+fn get_struct() -> Struct {
+    Struct { field: 0 }
+}
+fn get_drop_struct() -> DropStruct {
+    DropStruct { field: 0 }
+}
+
+unsafe fn unsafe_fn() -> i32 {
+    0
+}
+
+fn main() {
+    let s = get_struct();
+    let s2 = get_struct();
+
+    0;
+    s2;
+    Unit;
+    Tuple(0);
+    Struct { field: 0 };
+    Struct { ..s };
+    Union { a: 0 };
+    Enum::Tuple(0);
+    Enum::Struct { field: 0 };
+    5 + 6;
+    *&42;
+    &6;
+    (5, 6, 7);
+    box 42;
+    ..;
+    5..;
+    ..5;
+    5..6;
+    5..=6;
+    [42, 55];
+    [42, 55][1];
+    (42, 55).1;
+    [42; 55];
+    [42; 55][13];
+    let mut x = 0;
+    || x += 5;
+    let s: String = "foo".into();
+    FooString { s: s };
+
+    // Do not warn
+    get_number();
+    unsafe { unsafe_fn() };
+    DropUnit;
+    DropStruct { field: 0 };
+    DropTuple(0);
+    DropEnum::Tuple(0);
+    DropEnum::Struct { field: 0 };
+}
diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr
new file mode 100644
index 00000000000..834b9056e31
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_effect.stderr
@@ -0,0 +1,154 @@
+error: statement with no effect
+  --> $DIR/no_effect.rs:65:5
+   |
+LL |     0;
+   |     ^^
+   |
+   = note: `-D clippy::no-effect` implied by `-D warnings`
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:66:5
+   |
+LL |     s2;
+   |     ^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:67:5
+   |
+LL |     Unit;
+   |     ^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:68:5
+   |
+LL |     Tuple(0);
+   |     ^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:69:5
+   |
+LL |     Struct { field: 0 };
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:70:5
+   |
+LL |     Struct { ..s };
+   |     ^^^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:71:5
+   |
+LL |     Union { a: 0 };
+   |     ^^^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:72:5
+   |
+LL |     Enum::Tuple(0);
+   |     ^^^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:73:5
+   |
+LL |     Enum::Struct { field: 0 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:74:5
+   |
+LL |     5 + 6;
+   |     ^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:75:5
+   |
+LL |     *&42;
+   |     ^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:76:5
+   |
+LL |     &6;
+   |     ^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:77:5
+   |
+LL |     (5, 6, 7);
+   |     ^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:78:5
+   |
+LL |     box 42;
+   |     ^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:79:5
+   |
+LL |     ..;
+   |     ^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:80:5
+   |
+LL |     5..;
+   |     ^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:81:5
+   |
+LL |     ..5;
+   |     ^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:82:5
+   |
+LL |     5..6;
+   |     ^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:84:5
+   |
+LL |     [42, 55];
+   |     ^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:85:5
+   |
+LL |     [42, 55][1];
+   |     ^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:86:5
+   |
+LL |     (42, 55).1;
+   |     ^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:87:5
+   |
+LL |     [42; 55];
+   |     ^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:88:5
+   |
+LL |     [42; 55][13];
+   |     ^^^^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:90:5
+   |
+LL |     || x += 5;
+   |     ^^^^^^^^^^
+
+error: statement with no effect
+  --> $DIR/no_effect.rs:92:5
+   |
+LL |     FooString { s: s };
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
+
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.rs b/src/tools/clippy/tests/ui/non_expressive_names.rs
new file mode 100644
index 00000000000..58415b4aede
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_expressive_names.rs
@@ -0,0 +1,56 @@
+#![warn(clippy::all)]
+#![allow(unused, clippy::println_empty_string)]
+
+#[derive(Clone, Debug)]
+enum MaybeInst {
+    Split,
+    Split1(usize),
+    Split2(usize),
+}
+
+struct InstSplit {
+    uiae: usize,
+}
+
+impl MaybeInst {
+    fn fill(&mut self) {
+        let filled = match *self {
+            MaybeInst::Split1(goto1) => panic!(1),
+            MaybeInst::Split2(goto2) => panic!(2),
+            _ => unimplemented!(),
+        };
+        unimplemented!()
+    }
+}
+
+fn underscores_and_numbers() {
+    let _1 = 1; //~ERROR Consider a more descriptive name
+    let ____1 = 1; //~ERROR Consider a more descriptive name
+    let __1___2 = 12; //~ERROR Consider a more descriptive name
+    let _1_ok = 1;
+}
+
+fn issue2927() {
+    let args = 1;
+    format!("{:?}", 2);
+}
+
+fn issue3078() {
+    match "a" {
+        stringify!(a) => {},
+        _ => {},
+    }
+}
+
+struct Bar;
+
+impl Bar {
+    fn bar() {
+        let _1 = 1;
+        let ____1 = 1;
+        let __1___2 = 12;
+        let _1_ok = 1;
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stderr b/src/tools/clippy/tests/ui/non_expressive_names.stderr
new file mode 100644
index 00000000000..a0ca46f0efc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_expressive_names.stderr
@@ -0,0 +1,40 @@
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:27:9
+   |
+LL |     let _1 = 1; //~ERROR Consider a more descriptive name
+   |         ^^
+   |
+   = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings`
+
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:28:9
+   |
+LL |     let ____1 = 1; //~ERROR Consider a more descriptive name
+   |         ^^^^^
+
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:29:9
+   |
+LL |     let __1___2 = 12; //~ERROR Consider a more descriptive name
+   |         ^^^^^^^
+
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:49:13
+   |
+LL |         let _1 = 1;
+   |             ^^
+
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:50:13
+   |
+LL |         let ____1 = 1;
+   |             ^^^^^
+
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:51:13
+   |
+LL |         let __1___2 = 12;
+   |             ^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stdout b/src/tools/clippy/tests/ui/non_expressive_names.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/non_expressive_names.stdout
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
new file mode 100644
index 00000000000..7ea154cb9b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -0,0 +1,52 @@
+#![allow(unused, clippy::many_single_char_names)]
+#![warn(clippy::nonminimal_bool)]
+
+fn main() {
+    let a: bool = unimplemented!();
+    let b: bool = unimplemented!();
+    let c: bool = unimplemented!();
+    let d: bool = unimplemented!();
+    let e: bool = unimplemented!();
+    let _ = !true;
+    let _ = !false;
+    let _ = !!a;
+    let _ = false || a;
+    // don't lint on cfgs
+    let _ = cfg!(you_shall_not_not_pass) && a;
+    let _ = a || !b || !c || !d || !e;
+    let _ = !(!a && b);
+    let _ = !(!a || b);
+    let _ = !a && !(b && c);
+}
+
+fn equality_stuff() {
+    let a: i32 = unimplemented!();
+    let b: i32 = unimplemented!();
+    let c: i32 = unimplemented!();
+    let d: i32 = unimplemented!();
+    let _ = a == b && c == 5 && a == b;
+    let _ = a == b || c == 5 || a == b;
+    let _ = a == b && c == 5 && b == a;
+    let _ = a != b || !(a != b || c == d);
+    let _ = a != b && !(a != b && c == d);
+}
+
+fn issue3847(a: u32, b: u32) -> bool {
+    const THRESHOLD: u32 = 1_000;
+
+    if a < THRESHOLD && b >= THRESHOLD || a >= THRESHOLD && b < THRESHOLD {
+        return false;
+    }
+    true
+}
+
+fn issue4548() {
+    fn f(_i: u32, _j: u32) -> u32 {
+        unimplemented!();
+    }
+
+    let i = 0;
+    let j = 0;
+
+    if i != j && f(i, j) != 0 || i == j && f(i, j) != 1 {}
+}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
new file mode 100644
index 00000000000..d34d106cb2f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -0,0 +1,111 @@
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:10:13
+   |
+LL |     let _ = !true;
+   |             ^^^^^ help: try: `false`
+   |
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:11:13
+   |
+LL |     let _ = !false;
+   |             ^^^^^^ help: try: `true`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:12:13
+   |
+LL |     let _ = !!a;
+   |             ^^^ help: try: `a`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:13:13
+   |
+LL |     let _ = false || a;
+   |             ^^^^^^^^^^ help: try: `a`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:17:13
+   |
+LL |     let _ = !(!a && b);
+   |             ^^^^^^^^^^ help: try: `a || !b`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:18:13
+   |
+LL |     let _ = !(!a || b);
+   |             ^^^^^^^^^^ help: try: `a && !b`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:19:13
+   |
+LL |     let _ = !a && !(b && c);
+   |             ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:27:13
+   |
+LL |     let _ = a == b && c == 5 && a == b;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let _ = a == b && c == 5;
+   |             ^^^^^^^^^^^^^^^^
+LL |     let _ = !(a != b || c != 5);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:28:13
+   |
+LL |     let _ = a == b || c == 5 || a == b;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let _ = a == b || c == 5;
+   |             ^^^^^^^^^^^^^^^^
+LL |     let _ = !(a != b && c != 5);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:29:13
+   |
+LL |     let _ = a == b && c == 5 && b == a;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let _ = a == b && c == 5;
+   |             ^^^^^^^^^^^^^^^^
+LL |     let _ = !(a != b || c != 5);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:30:13
+   |
+LL |     let _ = a != b || !(a != b || c == d);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let _ = a != b || c != d;
+   |             ^^^^^^^^^^^^^^^^
+LL |     let _ = !(a == b && c == d);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool.rs:31:13
+   |
+LL |     let _ = a != b && !(a != b && c == d);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let _ = a != b && c != d;
+   |             ^^^^^^^^^^^^^^^^
+LL |     let _ = !(a == b || c == d);
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs
new file mode 100644
index 00000000000..4de48cd0879
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs
@@ -0,0 +1,110 @@
+#![allow(unused, clippy::many_single_char_names)]
+#![warn(clippy::nonminimal_bool)]
+
+fn methods_with_negation() {
+    let a: Option<i32> = unimplemented!();
+    let b: Result<i32, i32> = unimplemented!();
+    let _ = a.is_some();
+    let _ = !a.is_some();
+    let _ = a.is_none();
+    let _ = !a.is_none();
+    let _ = b.is_err();
+    let _ = !b.is_err();
+    let _ = b.is_ok();
+    let _ = !b.is_ok();
+    let c = false;
+    let _ = !(a.is_some() && !c);
+    let _ = !(a.is_some() || !c);
+    let _ = !(!c ^ c) || !a.is_some();
+    let _ = (!c ^ c) || !a.is_some();
+    let _ = !c ^ c || !a.is_some();
+}
+
+// Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638
+// clippy::nonminimal_bool should only check the built-in Result and Some type, not
+// any other types like the following.
+enum CustomResultOk<E> {
+    Ok,
+    Err(E),
+}
+enum CustomResultErr<E> {
+    Ok,
+    Err(E),
+}
+enum CustomSomeSome<T> {
+    Some(T),
+    None,
+}
+enum CustomSomeNone<T> {
+    Some(T),
+    None,
+}
+
+impl<E> CustomResultOk<E> {
+    pub fn is_ok(&self) -> bool {
+        true
+    }
+}
+
+impl<E> CustomResultErr<E> {
+    pub fn is_err(&self) -> bool {
+        true
+    }
+}
+
+impl<T> CustomSomeSome<T> {
+    pub fn is_some(&self) -> bool {
+        true
+    }
+}
+
+impl<T> CustomSomeNone<T> {
+    pub fn is_none(&self) -> bool {
+        true
+    }
+}
+
+fn dont_warn_for_custom_methods_with_negation() {
+    let res = CustomResultOk::Err("Error");
+    // Should not warn and suggest 'is_err()' because the type does not
+    // implement is_err().
+    if !res.is_ok() {}
+
+    let res = CustomResultErr::Err("Error");
+    // Should not warn and suggest 'is_ok()' because the type does not
+    // implement is_ok().
+    if !res.is_err() {}
+
+    let res = CustomSomeSome::Some("thing");
+    // Should not warn and suggest 'is_none()' because the type does not
+    // implement is_none().
+    if !res.is_some() {}
+
+    let res = CustomSomeNone::Some("thing");
+    // Should not warn and suggest 'is_some()' because the type does not
+    // implement is_some().
+    if !res.is_none() {}
+}
+
+// Only Built-in Result and Some types should suggest the negated alternative
+fn warn_for_built_in_methods_with_negation() {
+    let res: Result<usize, usize> = Ok(1);
+    if !res.is_ok() {}
+    if !res.is_err() {}
+
+    let res = Some(1);
+    if !res.is_some() {}
+    if !res.is_none() {}
+}
+
+#[allow(clippy::neg_cmp_op_on_partial_ord)]
+fn dont_warn_for_negated_partial_ord_comparison() {
+    let a: f64 = unimplemented!();
+    let b: f64 = unimplemented!();
+    let _ = !(a < b);
+    let _ = !(a <= b);
+    let _ = !(a > b);
+    let _ = !(a >= b);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr
new file mode 100644
index 00000000000..a2df889d623
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr
@@ -0,0 +1,82 @@
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:8:13
+   |
+LL |     let _ = !a.is_some();
+   |             ^^^^^^^^^^^^ help: try: `a.is_none()`
+   |
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:10:13
+   |
+LL |     let _ = !a.is_none();
+   |             ^^^^^^^^^^^^ help: try: `a.is_some()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:12:13
+   |
+LL |     let _ = !b.is_err();
+   |             ^^^^^^^^^^^ help: try: `b.is_ok()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:14:13
+   |
+LL |     let _ = !b.is_ok();
+   |             ^^^^^^^^^^ help: try: `b.is_err()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:16:13
+   |
+LL |     let _ = !(a.is_some() && !c);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:17:13
+   |
+LL |     let _ = !(a.is_some() || !c);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:18:26
+   |
+LL |     let _ = !(!c ^ c) || !a.is_some();
+   |                          ^^^^^^^^^^^^ help: try: `a.is_none()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:19:25
+   |
+LL |     let _ = (!c ^ c) || !a.is_some();
+   |                         ^^^^^^^^^^^^ help: try: `a.is_none()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:20:23
+   |
+LL |     let _ = !c ^ c || !a.is_some();
+   |                       ^^^^^^^^^^^^ help: try: `a.is_none()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:92:8
+   |
+LL |     if !res.is_ok() {}
+   |        ^^^^^^^^^^^^ help: try: `res.is_err()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:93:8
+   |
+LL |     if !res.is_err() {}
+   |        ^^^^^^^^^^^^^ help: try: `res.is_ok()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:96:8
+   |
+LL |     if !res.is_some() {}
+   |        ^^^^^^^^^^^^^^ help: try: `res.is_none()`
+
+error: this boolean expression can be simplified
+  --> $DIR/nonminimal_bool_methods.rs:97:8
+   |
+LL |     if !res.is_none() {}
+   |        ^^^^^^^^^^^^^^ help: try: `res.is_some()`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ok_expect.rs b/src/tools/clippy/tests/ui/ok_expect.rs
new file mode 100644
index 00000000000..ff68d38c73b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ok_expect.rs
@@ -0,0 +1,27 @@
+use std::io;
+
+struct MyError(()); // doesn't implement Debug
+
+#[derive(Debug)]
+struct MyErrorWithParam<T> {
+    x: T,
+}
+
+fn main() {
+    let res: Result<i32, ()> = Ok(0);
+    let _ = res.unwrap();
+
+    res.ok().expect("disaster!");
+    // the following should not warn, since `expect` isn't implemented unless
+    // the error type implements `Debug`
+    let res2: Result<i32, MyError> = Ok(0);
+    res2.ok().expect("oh noes!");
+    let res3: Result<u32, MyErrorWithParam<u8>> = Ok(0);
+    res3.ok().expect("whoof");
+    let res4: Result<u32, io::Error> = Ok(0);
+    res4.ok().expect("argh");
+    let res5: io::Result<u32> = Ok(0);
+    res5.ok().expect("oops");
+    let res6: Result<u32, &str> = Ok(0);
+    res6.ok().expect("meh");
+}
diff --git a/src/tools/clippy/tests/ui/ok_expect.stderr b/src/tools/clippy/tests/ui/ok_expect.stderr
new file mode 100644
index 00000000000..b02b28e7f68
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ok_expect.stderr
@@ -0,0 +1,43 @@
+error: called `ok().expect()` on a `Result` value
+  --> $DIR/ok_expect.rs:14:5
+   |
+LL |     res.ok().expect("disaster!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::ok-expect` implied by `-D warnings`
+   = help: you can call `expect()` directly on the `Result`
+
+error: called `ok().expect()` on a `Result` value
+  --> $DIR/ok_expect.rs:20:5
+   |
+LL |     res3.ok().expect("whoof");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: you can call `expect()` directly on the `Result`
+
+error: called `ok().expect()` on a `Result` value
+  --> $DIR/ok_expect.rs:22:5
+   |
+LL |     res4.ok().expect("argh");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: you can call `expect()` directly on the `Result`
+
+error: called `ok().expect()` on a `Result` value
+  --> $DIR/ok_expect.rs:24:5
+   |
+LL |     res5.ok().expect("oops");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: you can call `expect()` directly on the `Result`
+
+error: called `ok().expect()` on a `Result` value
+  --> $DIR/ok_expect.rs:26:5
+   |
+LL |     res6.ok().expect("meh");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: you can call `expect()` directly on the `Result`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs
new file mode 100644
index 00000000000..6605c967c8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/op_ref.rs
@@ -0,0 +1,58 @@
+#![allow(unused_variables, clippy::blacklisted_name)]
+#![warn(clippy::op_ref)]
+#![allow(clippy::many_single_char_names)]
+use std::collections::HashSet;
+use std::ops::BitAnd;
+
+fn main() {
+    let tracked_fds: HashSet<i32> = HashSet::new();
+    let new_fds = HashSet::new();
+    let unwanted = &tracked_fds - &new_fds;
+
+    let foo = &5 - &6;
+
+    let bar = String::new();
+    let bar = "foo" == &bar;
+
+    let a = "a".to_string();
+    let b = "a";
+
+    if b < &a {
+        println!("OK");
+    }
+
+    struct X(i32);
+    impl BitAnd for X {
+        type Output = X;
+        fn bitand(self, rhs: X) -> X {
+            X(self.0 & rhs.0)
+        }
+    }
+    impl<'a> BitAnd<&'a X> for X {
+        type Output = X;
+        fn bitand(self, rhs: &'a X) -> X {
+            X(self.0 & rhs.0)
+        }
+    }
+    let x = X(1);
+    let y = X(2);
+    let z = x & &y;
+
+    #[derive(Copy, Clone)]
+    struct Y(i32);
+    impl BitAnd for Y {
+        type Output = Y;
+        fn bitand(self, rhs: Y) -> Y {
+            Y(self.0 & rhs.0)
+        }
+    }
+    impl<'a> BitAnd<&'a Y> for Y {
+        type Output = Y;
+        fn bitand(self, rhs: &'a Y) -> Y {
+            Y(self.0 & rhs.0)
+        }
+    }
+    let x = Y(1);
+    let y = Y(2);
+    let z = x & &y;
+}
diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr
new file mode 100644
index 00000000000..a3a9adcc483
--- /dev/null
+++ b/src/tools/clippy/tests/ui/op_ref.stderr
@@ -0,0 +1,22 @@
+error: needlessly taken reference of both operands
+  --> $DIR/op_ref.rs:12:15
+   |
+LL |     let foo = &5 - &6;
+   |               ^^^^^^^
+   |
+   = note: `-D clippy::op-ref` implied by `-D warnings`
+help: use the values directly
+   |
+LL |     let foo = 5 - 6;
+   |               ^   ^
+
+error: taken reference of right operand
+  --> $DIR/op_ref.rs:57:13
+   |
+LL |     let z = x & &y;
+   |             ^^^^--
+   |                 |
+   |                 help: use the right value directly: `y`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/open_options.rs b/src/tools/clippy/tests/ui/open_options.rs
new file mode 100644
index 00000000000..9063fafbcd0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/open_options.rs
@@ -0,0 +1,14 @@
+use std::fs::OpenOptions;
+
+#[allow(unused_must_use)]
+#[warn(clippy::nonsensical_open_options)]
+fn main() {
+    OpenOptions::new().read(true).truncate(true).open("foo.txt");
+    OpenOptions::new().append(true).truncate(true).open("foo.txt");
+
+    OpenOptions::new().read(true).read(false).open("foo.txt");
+    OpenOptions::new().create(true).create(false).open("foo.txt");
+    OpenOptions::new().write(true).write(false).open("foo.txt");
+    OpenOptions::new().append(true).append(false).open("foo.txt");
+    OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
+}
diff --git a/src/tools/clippy/tests/ui/open_options.stderr b/src/tools/clippy/tests/ui/open_options.stderr
new file mode 100644
index 00000000000..26fe9f6fb20
--- /dev/null
+++ b/src/tools/clippy/tests/ui/open_options.stderr
@@ -0,0 +1,46 @@
+error: file opened with `truncate` and `read`
+  --> $DIR/open_options.rs:6:5
+   |
+LL |     OpenOptions::new().read(true).truncate(true).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::nonsensical-open-options` implied by `-D warnings`
+
+error: file opened with `append` and `truncate`
+  --> $DIR/open_options.rs:7:5
+   |
+LL |     OpenOptions::new().append(true).truncate(true).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the method `read` is called more than once
+  --> $DIR/open_options.rs:9:5
+   |
+LL |     OpenOptions::new().read(true).read(false).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the method `create` is called more than once
+  --> $DIR/open_options.rs:10:5
+   |
+LL |     OpenOptions::new().create(true).create(false).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the method `write` is called more than once
+  --> $DIR/open_options.rs:11:5
+   |
+LL |     OpenOptions::new().write(true).write(false).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the method `append` is called more than once
+  --> $DIR/open_options.rs:12:5
+   |
+LL |     OpenOptions::new().append(true).append(false).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the method `truncate` is called more than once
+  --> $DIR/open_options.rs:13:5
+   |
+LL |     OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_and_then_some.fixed b/src/tools/clippy/tests/ui/option_and_then_some.fixed
new file mode 100644
index 00000000000..035bc1e5465
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_and_then_some.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+#![deny(clippy::option_and_then_some)]
+
+// need a main anyway, use it get rid of unused warnings too
+pub fn main() {
+    let x = Some(5);
+    // the easiest cases
+    let _ = x;
+    let _ = x.map(|o| o + 1);
+    // and an easy counter-example
+    let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
+
+    // Different type
+    let x: Result<u32, &str> = Ok(1);
+    let _ = x.and_then(Ok);
+}
+
+pub fn foo() -> Option<String> {
+    let x = Some(String::from("hello"));
+    Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?)))
+}
+
+pub fn example2(x: bool) -> Option<&'static str> {
+    Some("a").and_then(|s| Some(if x { s } else { return None }))
+}
diff --git a/src/tools/clippy/tests/ui/option_and_then_some.rs b/src/tools/clippy/tests/ui/option_and_then_some.rs
new file mode 100644
index 00000000000..d49da7813c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_and_then_some.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+#![deny(clippy::option_and_then_some)]
+
+// need a main anyway, use it get rid of unused warnings too
+pub fn main() {
+    let x = Some(5);
+    // the easiest cases
+    let _ = x.and_then(Some);
+    let _ = x.and_then(|o| Some(o + 1));
+    // and an easy counter-example
+    let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
+
+    // Different type
+    let x: Result<u32, &str> = Ok(1);
+    let _ = x.and_then(Ok);
+}
+
+pub fn foo() -> Option<String> {
+    let x = Some(String::from("hello"));
+    Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?)))
+}
+
+pub fn example2(x: bool) -> Option<&'static str> {
+    Some("a").and_then(|s| Some(if x { s } else { return None }))
+}
diff --git a/src/tools/clippy/tests/ui/option_and_then_some.stderr b/src/tools/clippy/tests/ui/option_and_then_some.stderr
new file mode 100644
index 00000000000..47825491765
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_and_then_some.stderr
@@ -0,0 +1,20 @@
+error: using `Option.and_then(Some)`, which is a no-op
+  --> $DIR/option_and_then_some.rs:8:13
+   |
+LL |     let _ = x.and_then(Some);
+   |             ^^^^^^^^^^^^^^^^ help: use the expression directly: `x`
+   |
+note: the lint level is defined here
+  --> $DIR/option_and_then_some.rs:2:9
+   |
+LL | #![deny(clippy::option_and_then_some)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
+  --> $DIR/option_and_then_some.rs:9:13
+   |
+LL |     let _ = x.and_then(|o| Some(o + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
new file mode 100644
index 00000000000..076692e6445
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
@@ -0,0 +1,41 @@
+// run-rustfix
+
+#![allow(unused_imports, clippy::redundant_clone)]
+#![warn(clippy::option_as_ref_deref)]
+
+use std::ffi::{CString, OsString};
+use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+
+fn main() {
+    let mut opt = Some(String::from("123"));
+
+    let _ = opt.clone().as_deref().map(str::len);
+
+    #[rustfmt::skip]
+    let _ = opt.clone().as_deref()
+        .map(str::len);
+
+    let _ = opt.as_deref_mut();
+
+    let _ = opt.as_deref();
+    let _ = opt.as_deref();
+    let _ = opt.as_deref_mut();
+    let _ = opt.as_deref_mut();
+    let _ = Some(CString::new(vec![]).unwrap()).as_deref();
+    let _ = Some(OsString::new()).as_deref();
+    let _ = Some(PathBuf::new()).as_deref();
+    let _ = Some(Vec::<()>::new()).as_deref();
+    let _ = Some(Vec::<()>::new()).as_deref_mut();
+
+    let _ = opt.as_deref();
+    let _ = opt.clone().as_deref_mut().map(|x| x.len());
+
+    let vc = vec![String::new()];
+    let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
+
+    let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
+
+    let _ = opt.as_deref();
+    let _ = opt.as_deref_mut();
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.rs b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
new file mode 100644
index 00000000000..3bf5f715f83
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![allow(unused_imports, clippy::redundant_clone)]
+#![warn(clippy::option_as_ref_deref)]
+
+use std::ffi::{CString, OsString};
+use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+
+fn main() {
+    let mut opt = Some(String::from("123"));
+
+    let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
+
+    #[rustfmt::skip]
+    let _ = opt.clone()
+        .as_ref().map(
+            Deref::deref
+        )
+        .map(str::len);
+
+    let _ = opt.as_mut().map(DerefMut::deref_mut);
+
+    let _ = opt.as_ref().map(String::as_str);
+    let _ = opt.as_ref().map(|x| x.as_str());
+    let _ = opt.as_mut().map(String::as_mut_str);
+    let _ = opt.as_mut().map(|x| x.as_mut_str());
+    let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
+    let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
+    let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
+    let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
+    let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
+
+    let _ = opt.as_ref().map(|x| x.deref());
+    let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
+
+    let vc = vec![String::new()];
+    let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
+
+    let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
+
+    let _ = opt.as_ref().map(|x| &**x);
+    let _ = opt.as_mut().map(|x| &mut **x);
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
new file mode 100644
index 00000000000..a106582a633
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
@@ -0,0 +1,104 @@
+error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:13:13
+   |
+LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
+   |
+   = note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
+
+error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:16:13
+   |
+LL |       let _ = opt.clone()
+   |  _____________^
+LL | |         .as_ref().map(
+LL | |             Deref::deref
+LL | |         )
+   | |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
+
+error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:22:13
+   |
+LL |     let _ = opt.as_mut().map(DerefMut::deref_mut);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
+
+error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:24:13
+   |
+LL |     let _ = opt.as_ref().map(String::as_str);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:25:13
+   |
+LL |     let _ = opt.as_ref().map(|x| x.as_str());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:26:13
+   |
+LL |     let _ = opt.as_mut().map(String::as_mut_str);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
+
+error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:27:13
+   |
+LL |     let _ = opt.as_mut().map(|x| x.as_mut_str());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
+
+error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:28:13
+   |
+LL |     let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
+
+error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:29:13
+   |
+LL |     let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
+
+error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:30:13
+   |
+LL |     let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
+
+error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:31:13
+   |
+LL |     let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
+
+error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:32:13
+   |
+LL |     let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
+
+error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:34:13
+   |
+LL |     let _ = opt.as_ref().map(|x| x.deref());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:35:13
+   |
+LL |     let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
+
+error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:42:13
+   |
+LL |     let _ = opt.as_ref().map(|x| &**x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
+  --> $DIR/option_as_ref_deref.rs:43:13
+   |
+LL |     let _ = opt.as_mut().map(|x| &mut **x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs
new file mode 100644
index 00000000000..642c77460a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs
@@ -0,0 +1,23 @@
+// aux-build:macro_rules.rs
+#![warn(clippy::option_env_unwrap)]
+
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! option_env_unwrap {
+    ($env: expr) => {
+        option_env!($env).unwrap()
+    };
+    ($env: expr, $message: expr) => {
+        option_env!($env).expect($message)
+    };
+}
+
+fn main() {
+    let _ = option_env!("PATH").unwrap();
+    let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+    let _ = option_env_unwrap!("PATH");
+    let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
+    let _ = option_env_unwrap_external!("PATH");
+    let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
+}
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
new file mode 100644
index 00000000000..8de9c8a9d29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -0,0 +1,61 @@
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:17:13
+   |
+LL |     let _ = option_env!("PATH").unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-env-unwrap` implied by `-D warnings`
+   = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:18:13
+   |
+LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:9:9
+   |
+LL |         option_env!($env).unwrap()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     let _ = option_env_unwrap!("PATH");
+   |             -------------------------- in this macro invocation
+   |
+   = help: consider using the `env!` macro instead
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:12:9
+   |
+LL |         option_env!($env).expect($message)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
+   |             ----------------------------------------------------------------- in this macro invocation
+   |
+   = help: consider using the `env!` macro instead
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:21:13
+   |
+LL |     let _ = option_env_unwrap_external!("PATH");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:22:13
+   |
+LL |     let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.fixed b/src/tools/clippy/tests/ui/option_map_or_none.fixed
new file mode 100644
index 00000000000..decbae4e5af
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_or_none.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(clippy::option_and_then_some)]
+
+fn main() {
+    let opt = Some(1);
+
+    // Check `OPTION_MAP_OR_NONE`.
+    // Single line case.
+    let _ = opt.and_then(|x| Some(x + 1));
+    // Multi-line case.
+    #[rustfmt::skip]
+    let _ = opt.and_then(|x| {
+                        Some(x + 1)
+                       });
+}
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.rs b/src/tools/clippy/tests/ui/option_map_or_none.rs
new file mode 100644
index 00000000000..0f1d2218d5d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_or_none.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(clippy::option_and_then_some)]
+
+fn main() {
+    let opt = Some(1);
+
+    // Check `OPTION_MAP_OR_NONE`.
+    // Single line case.
+    let _ = opt.map_or(None, |x| Some(x + 1));
+    // Multi-line case.
+    #[rustfmt::skip]
+    let _ = opt.map_or(None, |x| {
+                        Some(x + 1)
+                       });
+}
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr
new file mode 100644
index 00000000000..6f707987dbc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr
@@ -0,0 +1,26 @@
+error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_or_none.rs:10:13
+   |
+LL |     let _ = opt.map_or(None, |x| Some(x + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(|x| Some(x + 1))`
+   |
+   = note: `-D clippy::option-map-or-none` implied by `-D warnings`
+
+error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_or_none.rs:13:13
+   |
+LL |       let _ = opt.map_or(None, |x| {
+   |  _____________^
+LL | |                         Some(x + 1)
+LL | |                        });
+   | |_________________________^
+   |
+help: try using `and_then` instead
+   |
+LL |     let _ = opt.and_then(|x| {
+LL |                         Some(x + 1)
+LL |                        });
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
new file mode 100644
index 00000000000..9a0da404cb6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
@@ -0,0 +1,84 @@
+// run-rustfix
+
+#![warn(clippy::option_map_unit_fn)]
+#![allow(unused)]
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+fn option() -> Option<usize> {
+    Some(10)
+}
+
+struct HasOption {
+    field: Option<usize>,
+}
+
+impl HasOption {
+    fn do_option_nothing(self: &Self, value: usize) {}
+
+    fn do_option_plus_one(self: &Self, value: usize) -> usize {
+        value + 1
+    }
+}
+#[rustfmt::skip]
+fn option_map_unit_fn() {
+    let x = HasOption { field: Some(10) };
+
+    x.field.map(plus_one);
+    let _ : Option<()> = x.field.map(do_nothing);
+
+    if let Some(x_field) = x.field { do_nothing(x_field) }
+
+    if let Some(x_field) = x.field { do_nothing(x_field) }
+
+    if let Some(x_field) = x.field { diverge(x_field) }
+
+    let captured = 10;
+    if let Some(value) = x.field { do_nothing(value + captured) };
+    let _ : Option<()> = x.field.map(|value| do_nothing(value + captured));
+
+    if let Some(value) = x.field { x.do_option_nothing(value + captured) }
+
+    if let Some(value) = x.field { x.do_option_plus_one(value + captured); }
+
+
+    if let Some(value) = x.field { do_nothing(value + captured) }
+
+    if let Some(value) = x.field { do_nothing(value + captured) }
+
+    if let Some(value) = x.field { do_nothing(value + captured); }
+
+    if let Some(value) = x.field { do_nothing(value + captured); }
+
+
+    if let Some(value) = x.field { diverge(value + captured) }
+
+    if let Some(value) = x.field { diverge(value + captured) }
+
+    if let Some(value) = x.field { diverge(value + captured); }
+
+    if let Some(value) = x.field { diverge(value + captured); }
+
+
+    x.field.map(|value| plus_one(value + captured));
+    x.field.map(|value| { plus_one(value + captured) });
+    if let Some(value) = x.field { let y = plus_one(value + captured); }
+
+    if let Some(value) = x.field { plus_one(value + captured); }
+
+    if let Some(value) = x.field { plus_one(value + captured); }
+
+
+    if let Some(ref value) = x.field { do_nothing(value + captured) }
+
+    if let Some(a) = option() { do_nothing(a) }}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
new file mode 100644
index 00000000000..58041b62df3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
@@ -0,0 +1,84 @@
+// run-rustfix
+
+#![warn(clippy::option_map_unit_fn)]
+#![allow(unused)]
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+fn option() -> Option<usize> {
+    Some(10)
+}
+
+struct HasOption {
+    field: Option<usize>,
+}
+
+impl HasOption {
+    fn do_option_nothing(self: &Self, value: usize) {}
+
+    fn do_option_plus_one(self: &Self, value: usize) -> usize {
+        value + 1
+    }
+}
+#[rustfmt::skip]
+fn option_map_unit_fn() {
+    let x = HasOption { field: Some(10) };
+
+    x.field.map(plus_one);
+    let _ : Option<()> = x.field.map(do_nothing);
+
+    x.field.map(do_nothing);
+
+    x.field.map(do_nothing);
+
+    x.field.map(diverge);
+
+    let captured = 10;
+    if let Some(value) = x.field { do_nothing(value + captured) };
+    let _ : Option<()> = x.field.map(|value| do_nothing(value + captured));
+
+    x.field.map(|value| x.do_option_nothing(value + captured));
+
+    x.field.map(|value| { x.do_option_plus_one(value + captured); });
+
+
+    x.field.map(|value| do_nothing(value + captured));
+
+    x.field.map(|value| { do_nothing(value + captured) });
+
+    x.field.map(|value| { do_nothing(value + captured); });
+
+    x.field.map(|value| { { do_nothing(value + captured); } });
+
+
+    x.field.map(|value| diverge(value + captured));
+
+    x.field.map(|value| { diverge(value + captured) });
+
+    x.field.map(|value| { diverge(value + captured); });
+
+    x.field.map(|value| { { diverge(value + captured); } });
+
+
+    x.field.map(|value| plus_one(value + captured));
+    x.field.map(|value| { plus_one(value + captured) });
+    x.field.map(|value| { let y = plus_one(value + captured); });
+
+    x.field.map(|value| { plus_one(value + captured); });
+
+    x.field.map(|value| { { plus_one(value + captured); } });
+
+
+    x.field.map(|ref value| { do_nothing(value + captured) });
+
+    option().map(do_nothing);}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
new file mode 100644
index 00000000000..1312c70b6d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
@@ -0,0 +1,148 @@
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:38:5
+   |
+LL |     x.field.map(do_nothing);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
+   |
+   = note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
+
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:40:5
+   |
+LL |     x.field.map(do_nothing);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
+
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:42:5
+   |
+LL |     x.field.map(diverge);
+   |     ^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:48:5
+   |
+LL |     x.field.map(|value| x.do_option_nothing(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:50:5
+   |
+LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:53:5
+   |
+LL |     x.field.map(|value| do_nothing(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:55:5
+   |
+LL |     x.field.map(|value| { do_nothing(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:57:5
+   |
+LL |     x.field.map(|value| { do_nothing(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:59:5
+   |
+LL |     x.field.map(|value| { { do_nothing(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:62:5
+   |
+LL |     x.field.map(|value| diverge(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:64:5
+   |
+LL |     x.field.map(|value| { diverge(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:66:5
+   |
+LL |     x.field.map(|value| { diverge(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:68:5
+   |
+LL |     x.field.map(|value| { { diverge(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:73:5
+   |
+LL |     x.field.map(|value| { let y = plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:75:5
+   |
+LL |     x.field.map(|value| { plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:77:5
+   |
+LL |     x.field.map(|value| { { plus_one(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
+
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:80:5
+   |
+LL |     x.field.map(|ref value| { do_nothing(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
+
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+  --> $DIR/option_map_unit_fn_fixable.rs:82:5
+   |
+LL |     option().map(do_nothing);}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Some(a) = option() { do_nothing(a) }`
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs
new file mode 100644
index 00000000000..20e6c15b18d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs
@@ -0,0 +1,39 @@
+#![warn(clippy::option_map_unit_fn)]
+#![allow(unused)]
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+#[rustfmt::skip]
+fn option_map_unit_fn() {
+
+    x.field.map(|value| { do_nothing(value); do_nothing(value) });
+
+    x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+
+    // Suggestion for the let block should be `{ ... }` as it's too difficult to build a
+    // proper suggestion for these cases
+    x.field.map(|value| {
+        do_nothing(value);
+        do_nothing(value)
+    });
+    x.field.map(|value| { do_nothing(value); do_nothing(value); });
+
+    // The following should suggest `if let Some(_X) ...` as it's difficult to generate a proper let variable name for them
+    Some(42).map(diverge);
+    "12".parse::<i32>().ok().map(diverge);
+    Some(plus_one(1)).map(do_nothing);
+
+    // Should suggest `if let Some(_y) ...` to not override the existing foo variable
+    let y = Some(42);
+    y.map(do_nothing);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr
new file mode 100644
index 00000000000..a53f5889c58
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr
@@ -0,0 +1,27 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/option_map_unit_fn_unfixable.rs:17:5
+   |
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
+   |     ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/option_map_unit_fn_unfixable.rs:19:5
+   |
+LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+   |     ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/option_map_unit_fn_unfixable.rs:23:5
+   |
+LL |     x.field.map(|value| {
+   |     ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/option_map_unit_fn_unfixable.rs:27:5
+   |
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
+   |     ^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/tools/clippy/tests/ui/option_map_unwrap_or.rs b/src/tools/clippy/tests/ui/option_map_unwrap_or.rs
new file mode 100644
index 00000000000..0364d83663a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unwrap_or.rs
@@ -0,0 +1,88 @@
+// FIXME: Add "run-rustfix" once it's supported for multipart suggestions
+// aux-build:option_helpers.rs
+
+#![warn(clippy::option_map_unwrap_or, clippy::option_map_unwrap_or_else)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use std::collections::HashMap;
+
+/// Checks implementation of the following lints:
+/// * `OPTION_MAP_UNWRAP_OR`
+/// * `OPTION_MAP_UNWRAP_OR_ELSE`
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check `OPTION_MAP_UNWRAP_OR`.
+    // Single line case.
+    let _ = opt.map(|x| x + 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or(0);
+    // Multi-line cases.
+    let _ = opt.map(|x| {
+        x + 1
+    }
+    ).unwrap_or(0);
+    let _ = opt.map(|x| x + 1)
+        .unwrap_or({
+            0
+        });
+    // Single line `map(f).unwrap_or(None)` case.
+    let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
+    // Multi-line `map(f).unwrap_or(None)` cases.
+    let _ = opt.map(|x| {
+        Some(x + 1)
+    }
+    ).unwrap_or(None);
+    let _ = opt
+        .map(|x| Some(x + 1))
+        .unwrap_or(None);
+    // macro case
+    let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
+
+    // Should not lint if not copyable
+    let id: String = "identifier".to_string();
+    let _ = Some("prefix").map(|p| format!("{}.{}", p, id)).unwrap_or(id);
+    // ...but DO lint if the `unwrap_or` argument is not used in the `map`
+    let id: String = "identifier".to_string();
+    let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
+
+    // Check OPTION_MAP_UNWRAP_OR_ELSE
+    // single line case
+    let _ = opt.map(|x| x + 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or_else(|| 0);
+    // Multi-line cases.
+    let _ = opt.map(|x| {
+        x + 1
+    }
+    ).unwrap_or_else(|| 0);
+    let _ = opt.map(|x| x + 1)
+        .unwrap_or_else(||
+            0
+        );
+    // Macro case.
+    // Should not lint.
+    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
+
+    // Issue #4144
+    {
+        let mut frequencies = HashMap::new();
+        let word = "foo";
+
+        frequencies
+            .get_mut(word)
+            .map(|count| {
+                *count += 1;
+            })
+            .unwrap_or_else(|| {
+                frequencies.insert(word.to_owned(), 1);
+            });
+    }
+}
+
+fn main() {
+    option_methods();
+}
diff --git a/src/tools/clippy/tests/ui/option_map_unwrap_or.stderr b/src/tools/clippy/tests/ui/option_map_unwrap_or.stderr
new file mode 100644
index 00000000000..f05f2893de2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_map_unwrap_or.stderr
@@ -0,0 +1,138 @@
+error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:20:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |         // Should lint even though this call is on a separate line.
+LL | |         .unwrap_or(0);
+   | |_____________________^
+   |
+   = note: `-D clippy::option-map-unwrap-or` implied by `-D warnings`
+help: use `map_or(a, f)` instead
+   |
+LL |     let _ = opt.map_or(0, |x| x + 1);
+   |                 ^^^^^^ ^^          --
+
+error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:24:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |         x + 1
+LL | |     }
+LL | |     ).unwrap_or(0);
+   | |__________________^
+   |
+help: use `map_or(a, f)` instead
+   |
+LL |     let _ = opt.map_or(0, |x| {
+LL |         x + 1
+LL |     }
+LL |     );
+   |
+
+error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:28:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |         .unwrap_or({
+LL | |             0
+LL | |         });
+   | |__________^
+   |
+help: use `map_or(a, f)` instead
+   |
+LL |     let _ = opt.map_or({
+LL |             0
+LL |         }, |x| x + 1);
+   |
+
+error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_unwrap_or.rs:33:13
+   |
+LL |     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `and_then(f)` instead
+   |
+LL |     let _ = opt.and_then(|x| Some(x + 1));
+   |                 ^^^^^^^^                --
+
+error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_unwrap_or.rs:35:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |         Some(x + 1)
+LL | |     }
+LL | |     ).unwrap_or(None);
+   | |_____________________^
+   |
+help: use `and_then(f)` instead
+   |
+LL |     let _ = opt.and_then(|x| {
+LL |         Some(x + 1)
+LL |     }
+LL |     );
+   |
+
+error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_unwrap_or.rs:39:13
+   |
+LL |       let _ = opt
+   |  _____________^
+LL | |         .map(|x| Some(x + 1))
+LL | |         .unwrap_or(None);
+   | |________________________^
+   |
+help: use `and_then(f)` instead
+   |
+LL |         .and_then(|x| Some(x + 1));
+   |          ^^^^^^^^                --
+
+error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:50:13
+   |
+LL |     let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `map_or(a, f)` instead
+   |
+LL |     let _ = Some("prefix").map_or(id, |p| format!("{}.", p));
+   |                            ^^^^^^ ^^^                      --
+
+error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:54:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |         // Should lint even though this call is on a separate line.
+LL | |         .unwrap_or_else(|| 0);
+   | |_____________________________^
+   |
+   = note: `-D clippy::option-map-unwrap-or-else` implied by `-D warnings`
+   = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)`
+
+error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:58:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |         x + 1
+LL | |     }
+LL | |     ).unwrap_or_else(|| 0);
+   | |__________________________^
+
+error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead
+  --> $DIR/option_map_unwrap_or.rs:62:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |         .unwrap_or_else(||
+LL | |             0
+LL | |         );
+   | |_________^
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_option.rs b/src/tools/clippy/tests/ui/option_option.rs
new file mode 100644
index 00000000000..904c50e1403
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_option.rs
@@ -0,0 +1,62 @@
+#![deny(clippy::option_option)]
+
+fn input(_: Option<Option<u8>>) {}
+
+fn output() -> Option<Option<u8>> {
+    None
+}
+
+fn output_nested() -> Vec<Option<Option<u8>>> {
+    vec![None]
+}
+
+// The lint only generates one warning for this
+fn output_nested_nested() -> Option<Option<Option<u8>>> {
+    None
+}
+
+struct Struct {
+    x: Option<Option<u8>>,
+}
+
+impl Struct {
+    fn struct_fn() -> Option<Option<u8>> {
+        None
+    }
+}
+
+trait Trait {
+    fn trait_fn() -> Option<Option<u8>>;
+}
+
+enum Enum {
+    Tuple(Option<Option<u8>>),
+    Struct { x: Option<Option<u8>> },
+}
+
+// The lint allows this
+type OptionOption = Option<Option<u32>>;
+
+// The lint allows this
+fn output_type_alias() -> OptionOption {
+    None
+}
+
+// The line allows this
+impl Trait for Struct {
+    fn trait_fn() -> Option<Option<u8>> {
+        None
+    }
+}
+
+fn main() {
+    input(None);
+    output();
+    output_nested();
+
+    // The lint allows this
+    let local: Option<Option<u8>> = None;
+
+    // The lint allows this
+    let expr = Some(Some(true));
+}
diff --git a/src/tools/clippy/tests/ui/option_option.stderr b/src/tools/clippy/tests/ui/option_option.stderr
new file mode 100644
index 00000000000..79db186d7ea
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_option.stderr
@@ -0,0 +1,62 @@
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:3:13
+   |
+LL | fn input(_: Option<Option<u8>>) {}
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/option_option.rs:1:9
+   |
+LL | #![deny(clippy::option_option)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:5:16
+   |
+LL | fn output() -> Option<Option<u8>> {
+   |                ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:9:27
+   |
+LL | fn output_nested() -> Vec<Option<Option<u8>>> {
+   |                           ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:14:30
+   |
+LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:19:8
+   |
+LL |     x: Option<Option<u8>>,
+   |        ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:23:23
+   |
+LL |     fn struct_fn() -> Option<Option<u8>> {
+   |                       ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:29:22
+   |
+LL |     fn trait_fn() -> Option<Option<u8>>;
+   |                      ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:33:11
+   |
+LL |     Tuple(Option<Option<u8>>),
+   |           ^^^^^^^^^^^^^^^^^^
+
+error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
+  --> $DIR/option_option.rs:34:17
+   |
+LL |     Struct { x: Option<Option<u8>> },
+   |                 ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
new file mode 100644
index 00000000000..8ea03fe4261
--- /dev/null
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -0,0 +1,110 @@
+// run-rustfix
+
+#![warn(clippy::or_fun_call)]
+#![allow(dead_code)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::time::Duration;
+
+/// Checks implementation of the `OR_FUN_CALL` lint.
+fn or_fun_call() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Foo {
+            Foo
+        }
+    }
+
+    enum Enum {
+        A(i32),
+    }
+
+    fn make<T>() -> T {
+        unimplemented!();
+    }
+
+    let with_enum = Some(Enum::A(1));
+    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));
+
+    let with_constructor = Some(vec![1]);
+    with_constructor.unwrap_or_else(make);
+
+    let with_new = Some(vec![1]);
+    with_new.unwrap_or_default();
+
+    let with_const_args = Some(vec![1]);
+    with_const_args.unwrap_or_else(|| Vec::with_capacity(12));
+
+    let with_err: Result<_, ()> = Ok(vec![1]);
+    with_err.unwrap_or_else(|_| make());
+
+    let with_err_args: Result<_, ()> = Ok(vec![1]);
+    with_err_args.unwrap_or_else(|_| Vec::with_capacity(12));
+
+    let with_default_trait = Some(1);
+    with_default_trait.unwrap_or_default();
+
+    let with_default_type = Some(1);
+    with_default_type.unwrap_or_default();
+
+    let with_vec = Some(vec![1]);
+    with_vec.unwrap_or_default();
+
+    let without_default = Some(Foo);
+    without_default.unwrap_or_else(Foo::new);
+
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert_with(String::new);
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert_with(String::new);
+
+    let stringy = Some(String::from(""));
+    let _ = stringy.unwrap_or_else(|| "".to_owned());
+
+    let opt = Some(1);
+    let hello = "Hello";
+    let _ = opt.ok_or(format!("{} world.", hello));
+}
+
+struct Foo(u8);
+struct Bar(String, Duration);
+#[rustfmt::skip]
+fn test_or_with_ctors() {
+    let opt = Some(1);
+    let opt_opt = Some(Some(1));
+    // we also test for const promotion, this makes sure we don't hit that
+    let two = 2;
+
+    let _ = opt_opt.unwrap_or(Some(2));
+    let _ = opt_opt.unwrap_or(Some(two));
+    let _ = opt.ok_or(Some(2));
+    let _ = opt.ok_or(Some(two));
+    let _ = opt.ok_or(Foo(2));
+    let _ = opt.ok_or(Foo(two));
+    let _ = opt.or(Some(2));
+    let _ = opt.or(Some(two));
+
+    let _ = Some("a".to_string()).or_else(|| Some("b".to_string()));
+
+    let b = "b".to_string();
+    let _ = Some(Bar("a".to_string(), Duration::from_secs(1)))
+        .or(Some(Bar(b, Duration::from_secs(2))));
+}
+
+// Issue 4514 - early return
+fn f() -> Option<()> {
+    let a = Some(1);
+    let b = 1i32;
+
+    let _ = a.unwrap_or(b.checked_mul(3)?.min(240));
+
+    Some(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
new file mode 100644
index 00000000000..7599b945a91
--- /dev/null
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -0,0 +1,110 @@
+// run-rustfix
+
+#![warn(clippy::or_fun_call)]
+#![allow(dead_code)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::time::Duration;
+
+/// Checks implementation of the `OR_FUN_CALL` lint.
+fn or_fun_call() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Foo {
+            Foo
+        }
+    }
+
+    enum Enum {
+        A(i32),
+    }
+
+    fn make<T>() -> T {
+        unimplemented!();
+    }
+
+    let with_enum = Some(Enum::A(1));
+    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));
+
+    let with_constructor = Some(vec![1]);
+    with_constructor.unwrap_or(make());
+
+    let with_new = Some(vec![1]);
+    with_new.unwrap_or(Vec::new());
+
+    let with_const_args = Some(vec![1]);
+    with_const_args.unwrap_or(Vec::with_capacity(12));
+
+    let with_err: Result<_, ()> = Ok(vec![1]);
+    with_err.unwrap_or(make());
+
+    let with_err_args: Result<_, ()> = Ok(vec![1]);
+    with_err_args.unwrap_or(Vec::with_capacity(12));
+
+    let with_default_trait = Some(1);
+    with_default_trait.unwrap_or(Default::default());
+
+    let with_default_type = Some(1);
+    with_default_type.unwrap_or(u64::default());
+
+    let with_vec = Some(vec![1]);
+    with_vec.unwrap_or(vec![]);
+
+    let without_default = Some(Foo);
+    without_default.unwrap_or(Foo::new());
+
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
+
+    let stringy = Some(String::from(""));
+    let _ = stringy.unwrap_or("".to_owned());
+
+    let opt = Some(1);
+    let hello = "Hello";
+    let _ = opt.ok_or(format!("{} world.", hello));
+}
+
+struct Foo(u8);
+struct Bar(String, Duration);
+#[rustfmt::skip]
+fn test_or_with_ctors() {
+    let opt = Some(1);
+    let opt_opt = Some(Some(1));
+    // we also test for const promotion, this makes sure we don't hit that
+    let two = 2;
+
+    let _ = opt_opt.unwrap_or(Some(2));
+    let _ = opt_opt.unwrap_or(Some(two));
+    let _ = opt.ok_or(Some(2));
+    let _ = opt.ok_or(Some(two));
+    let _ = opt.ok_or(Foo(2));
+    let _ = opt.ok_or(Foo(two));
+    let _ = opt.or(Some(2));
+    let _ = opt.or(Some(two));
+
+    let _ = Some("a".to_string()).or(Some("b".to_string()));
+
+    let b = "b".to_string();
+    let _ = Some(Bar("a".to_string(), Duration::from_secs(1)))
+        .or(Some(Bar(b, Duration::from_secs(2))));
+}
+
+// Issue 4514 - early return
+fn f() -> Option<()> {
+    let a = Some(1);
+    let b = 1i32;
+
+    let _ = a.unwrap_or(b.checked_mul(3)?.min(240));
+
+    Some(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
new file mode 100644
index 00000000000..96d55771e6c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -0,0 +1,82 @@
+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
+   |
+LL |     with_new.unwrap_or(Vec::new());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:41:21
+   |
+LL |     with_const_args.unwrap_or(Vec::with_capacity(12));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:44:14
+   |
+LL |     with_err.unwrap_or(make());
+   |              ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:47:19
+   |
+LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
+
+error: use of `unwrap_or` followed by a call to `default`
+  --> $DIR/or_fun_call.rs:50:5
+   |
+LL |     with_default_trait.unwrap_or(Default::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `default`
+  --> $DIR/or_fun_call.rs:53:5
+   |
+LL |     with_default_type.unwrap_or(u64::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:56:5
+   |
+LL |     with_vec.unwrap_or(vec![]);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:59:21
+   |
+LL |     without_default.unwrap_or(Foo::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:62:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:65:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:68:21
+   |
+LL |     let _ = stringy.unwrap_or("".to_owned());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+
+error: use of `or` followed by a function call
+  --> $DIR/or_fun_call.rs:93:35
+   |
+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
+
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs
new file mode 100644
index 00000000000..f20a0ede113
--- /dev/null
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs
@@ -0,0 +1,11 @@
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(clippy::no_effect, const_err)]
+
+fn main() {
+    let x = [1, 2, 3, 4];
+
+    // issue 3102
+    let num = 1;
+    &x[num..10]; // should trigger out of bounds error
+    &x[10..num]; // should trigger out of bounds error
+}
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr
new file mode 100644
index 00000000000..516c1df40be
--- /dev/null
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.stderr
@@ -0,0 +1,16 @@
+error: range is out of bounds
+  --> $DIR/issue-3102.rs:9:13
+   |
+LL |     &x[num..10]; // should trigger out of bounds error
+   |             ^^
+   |
+   = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
+
+error: range is out of bounds
+  --> $DIR/issue-3102.rs:10:8
+   |
+LL |     &x[10..num]; // should trigger out of bounds error
+   |        ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs
new file mode 100644
index 00000000000..590e578d758
--- /dev/null
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs
@@ -0,0 +1,22 @@
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation, const_err)]
+
+fn main() {
+    let x = [1, 2, 3, 4];
+
+    &x[..=4];
+    &x[1..5];
+    &x[5..];
+    &x[..5];
+    &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>();
+    &x[0..=4];
+
+    &x[4..]; // Ok, should not produce stderr.
+    &x[..4]; // Ok, should not produce stderr.
+    &x[..]; // Ok, should not produce stderr.
+    &x[1..]; // Ok, should not produce stderr.
+    &x[2..].iter().map(|x| 2 * x).collect::<Vec<i32>>(); // Ok, should not produce stderr.
+
+    &x[0..].get(..3); // Ok, should not produce stderr.
+    &x[0..3]; // Ok, should not produce stderr.
+}
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr
new file mode 100644
index 00000000000..3d95afcdab2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr
@@ -0,0 +1,40 @@
+error: range is out of bounds
+  --> $DIR/simple.rs:7:11
+   |
+LL |     &x[..=4];
+   |           ^
+   |
+   = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
+
+error: range is out of bounds
+  --> $DIR/simple.rs:8:11
+   |
+LL |     &x[1..5];
+   |           ^
+
+error: range is out of bounds
+  --> $DIR/simple.rs:9:8
+   |
+LL |     &x[5..];
+   |        ^
+
+error: range is out of bounds
+  --> $DIR/simple.rs:10:10
+   |
+LL |     &x[..5];
+   |          ^
+
+error: range is out of bounds
+  --> $DIR/simple.rs:11:8
+   |
+LL |     &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>();
+   |        ^
+
+error: range is out of bounds
+  --> $DIR/simple.rs:12:12
+   |
+LL |     &x[0..=4];
+   |            ^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/outer_expn_data.fixed b/src/tools/clippy/tests/ui/outer_expn_data.fixed
new file mode 100644
index 00000000000..999a19b289e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/outer_expn_data.fixed
@@ -0,0 +1,28 @@
+// run-rustfix
+
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+declare_lint! {
+    pub TEST_LINT,
+    Warn,
+    ""
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        let _ = expr.span.ctxt().outer_expn_data();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/outer_expn_data.rs b/src/tools/clippy/tests/ui/outer_expn_data.rs
new file mode 100644
index 00000000000..5405d475d1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/outer_expn_data.rs
@@ -0,0 +1,28 @@
+// run-rustfix
+
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+
+declare_lint! {
+    pub TEST_LINT,
+    Warn,
+    ""
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        let _ = expr.span.ctxt().outer_expn().expn_data();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/outer_expn_data.stderr b/src/tools/clippy/tests/ui/outer_expn_data.stderr
new file mode 100644
index 00000000000..56b6ce1f78e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/outer_expn_data.stderr
@@ -0,0 +1,15 @@
+error: usage of `outer_expn().expn_data()`
+  --> $DIR/outer_expn_data.rs:24:34
+   |
+LL |         let _ = expr.span.ctxt().outer_expn().expn_data();
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `outer_expn_data()`
+   |
+note: the lint level is defined here
+  --> $DIR/outer_expn_data.rs:3:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::outer_expn_expn_data)]` implied by `#[deny(clippy::internal)]`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.rs b/src/tools/clippy/tests/ui/overflow_check_conditional.rs
new file mode 100644
index 00000000000..84332040dba
--- /dev/null
+++ b/src/tools/clippy/tests/ui/overflow_check_conditional.rs
@@ -0,0 +1,26 @@
+#![allow(clippy::many_single_char_names)]
+#![warn(clippy::overflow_check_conditional)]
+
+fn main() {
+    let a: u32 = 1;
+    let b: u32 = 2;
+    let c: u32 = 3;
+    if a + b < a {}
+    if a > a + b {}
+    if a + b < b {}
+    if b > a + b {}
+    if a - b > b {}
+    if b < a - b {}
+    if a - b > a {}
+    if a < a - b {}
+    if a + b < c {}
+    if c > a + b {}
+    if a - b < c {}
+    if c > a - b {}
+    let i = 1.1;
+    let j = 2.2;
+    if i + j < i {}
+    if i - j < i {}
+    if i > i + j {}
+    if i - j < i {}
+}
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
new file mode 100644
index 00000000000..ad66135d326
--- /dev/null
+++ b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
@@ -0,0 +1,52 @@
+error: You are trying to use classic C overflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:8:8
+   |
+LL |     if a + b < a {}
+   |        ^^^^^^^^^
+   |
+   = note: `-D clippy::overflow-check-conditional` implied by `-D warnings`
+
+error: You are trying to use classic C overflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:9:8
+   |
+LL |     if a > a + b {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C overflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:10:8
+   |
+LL |     if a + b < b {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C overflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:11:8
+   |
+LL |     if b > a + b {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C underflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:12:8
+   |
+LL |     if a - b > b {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C underflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:13:8
+   |
+LL |     if b < a - b {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C underflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:14:8
+   |
+LL |     if a - b > a {}
+   |        ^^^^^^^^^
+
+error: You are trying to use classic C underflow conditions that will fail in Rust.
+  --> $DIR/overflow_check_conditional.rs:15:8
+   |
+LL |     if a < a - b {}
+   |        ^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/panic.rs b/src/tools/clippy/tests/ui/panic.rs
new file mode 100644
index 00000000000..6e004aa9a92
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panic.rs
@@ -0,0 +1,61 @@
+#![warn(clippy::panic_params)]
+#![allow(clippy::assertions_on_constants)]
+fn missing() {
+    if true {
+        panic!("{}");
+    } else if false {
+        panic!("{:?}");
+    } else {
+        assert!(true, "here be missing values: {}");
+    }
+
+    panic!("{{{this}}}");
+}
+
+fn ok_single() {
+    panic!("foo bar");
+}
+
+fn ok_inner() {
+    // Test for #768
+    assert!("foo bar".contains(&format!("foo {}", "bar")));
+}
+
+fn ok_multiple() {
+    panic!("{}", "This is {ok}");
+}
+
+fn ok_bracket() {
+    match 42 {
+        1337 => panic!("{so is this"),
+        666 => panic!("so is this}"),
+        _ => panic!("}so is that{"),
+    }
+}
+
+const ONE: u32 = 1;
+
+fn ok_nomsg() {
+    assert!({ 1 == ONE });
+    assert!(if 1 == ONE { ONE == 1 } else { false });
+}
+
+fn ok_escaped() {
+    panic!("{{ why should this not be ok? }}");
+    panic!(" or {{ that ?");
+    panic!(" or }} this ?");
+    panic!(" {or {{ that ?");
+    panic!(" }or }} this ?");
+    panic!("{{ test }");
+    panic!("{case }}");
+}
+
+fn main() {
+    missing();
+    ok_single();
+    ok_multiple();
+    ok_bracket();
+    ok_inner();
+    ok_nomsg();
+    ok_escaped();
+}
diff --git a/src/tools/clippy/tests/ui/panic.stderr b/src/tools/clippy/tests/ui/panic.stderr
new file mode 100644
index 00000000000..1f8ff8ccf55
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panic.stderr
@@ -0,0 +1,28 @@
+error: you probably are missing some parameter in your format string
+  --> $DIR/panic.rs:5:16
+   |
+LL |         panic!("{}");
+   |                ^^^^
+   |
+   = note: `-D clippy::panic-params` implied by `-D warnings`
+
+error: you probably are missing some parameter in your format string
+  --> $DIR/panic.rs:7:16
+   |
+LL |         panic!("{:?}");
+   |                ^^^^^^
+
+error: you probably are missing some parameter in your format string
+  --> $DIR/panic.rs:9:23
+   |
+LL |         assert!(true, "here be missing values: {}");
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you probably are missing some parameter in your format string
+  --> $DIR/panic.rs:12:12
+   |
+LL |     panic!("{{{this}}}");
+   |            ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs
new file mode 100644
index 00000000000..dabb695368d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_macros.rs
@@ -0,0 +1,33 @@
+#![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)]
+#![allow(clippy::assertions_on_constants)]
+
+fn panic() {
+    let a = 2;
+    panic!();
+    let b = a + 2;
+}
+
+fn todo() {
+    let a = 2;
+    todo!();
+    let b = a + 2;
+}
+
+fn unimplemented() {
+    let a = 2;
+    unimplemented!();
+    let b = a + 2;
+}
+
+fn unreachable() {
+    let a = 2;
+    unreachable!();
+    let b = a + 2;
+}
+
+fn main() {
+    panic();
+    todo();
+    unimplemented();
+    unreachable();
+}
diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr
new file mode 100644
index 00000000000..72319bc7e45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_macros.stderr
@@ -0,0 +1,34 @@
+error: `panic` should not be present in production code
+  --> $DIR/panicking_macros.rs:6:5
+   |
+LL |     panic!();
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::panic` implied by `-D warnings`
+
+error: `todo` should not be present in production code
+  --> $DIR/panicking_macros.rs:12:5
+   |
+LL |     todo!();
+   |     ^^^^^^^^
+   |
+   = note: `-D clippy::todo` implied by `-D warnings`
+
+error: `unimplemented` should not be present in production code
+  --> $DIR/panicking_macros.rs:18:5
+   |
+LL |     unimplemented!();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unimplemented` implied by `-D warnings`
+
+error: `unreachable` should not be present in production code
+  --> $DIR/panicking_macros.rs:24:5
+   |
+LL |     unreachable!();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unreachable` implied by `-D warnings`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/partialeq_ne_impl.rs b/src/tools/clippy/tests/ui/partialeq_ne_impl.rs
new file mode 100644
index 00000000000..1338d3c74d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_ne_impl.rs
@@ -0,0 +1,26 @@
+#![allow(dead_code)]
+
+struct Foo;
+
+impl PartialEq for Foo {
+    fn eq(&self, _: &Foo) -> bool {
+        true
+    }
+    fn ne(&self, _: &Foo) -> bool {
+        false
+    }
+}
+
+struct Bar;
+
+impl PartialEq for Bar {
+    fn eq(&self, _: &Bar) -> bool {
+        true
+    }
+    #[allow(clippy::partialeq_ne_impl)]
+    fn ne(&self, _: &Bar) -> bool {
+        false
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr b/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr
new file mode 100644
index 00000000000..b92da4511b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_ne_impl.stderr
@@ -0,0 +1,12 @@
+error: re-implementing `PartialEq::ne` is unnecessary
+  --> $DIR/partialeq_ne_impl.rs:9:5
+   |
+LL | /     fn ne(&self, _: &Foo) -> bool {
+LL | |         false
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::partialeq-ne-impl` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed
new file mode 100644
index 00000000000..ef8856830fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+use std::path::PathBuf;
+
+#[warn(clippy::all, clippy::path_buf_push_overwrite)]
+fn main() {
+    let mut x = PathBuf::from("/foo");
+    x.push("bar");
+}
diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs
new file mode 100644
index 00000000000..6e2d483f454
--- /dev/null
+++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+use std::path::PathBuf;
+
+#[warn(clippy::all, clippy::path_buf_push_overwrite)]
+fn main() {
+    let mut x = PathBuf::from("/foo");
+    x.push("/bar");
+}
diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr
new file mode 100644
index 00000000000..09b18d71baf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.stderr
@@ -0,0 +1,10 @@
+error: Calling `push` with '/' or '/' (file system root) will overwrite the previous path definition
+  --> $DIR/path_buf_push_overwrite.rs:7:12
+   |
+LL |     x.push("/bar");
+   |            ^^^^^^ help: try: `"bar"`
+   |
+   = note: `-D clippy::path-buf-push-overwrite` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed
new file mode 100644
index 00000000000..f2238815449
--- /dev/null
+++ b/src/tools/clippy/tests/ui/patterns.fixed
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused)]
+#![warn(clippy::all)]
+
+fn main() {
+    let v = Some(true);
+    let s = [0, 1, 2, 3, 4];
+    match v {
+        Some(x) => (),
+        y => (),
+    }
+    match v {
+        Some(x) => (),
+        y @ None => (), // no error
+    }
+    match s {
+        [x, inside @ .., y] => (), // no error
+        [..] => (),
+    }
+
+    let mut mutv = vec![1, 2, 3];
+
+    // required "ref" left out in suggestion: #5271
+    match mutv {
+        ref mut x => {
+            x.push(4);
+            println!("vec: {:?}", x);
+        },
+        ref y if y == &vec![0] => (),
+    }
+
+    match mutv {
+        ref x => println!("vec: {:?}", x),
+        ref y if y == &vec![0] => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs
new file mode 100644
index 00000000000..5848ecd38d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/patterns.rs
@@ -0,0 +1,36 @@
+// run-rustfix
+#![allow(unused)]
+#![warn(clippy::all)]
+
+fn main() {
+    let v = Some(true);
+    let s = [0, 1, 2, 3, 4];
+    match v {
+        Some(x) => (),
+        y @ _ => (),
+    }
+    match v {
+        Some(x) => (),
+        y @ None => (), // no error
+    }
+    match s {
+        [x, inside @ .., y] => (), // no error
+        [..] => (),
+    }
+
+    let mut mutv = vec![1, 2, 3];
+
+    // required "ref" left out in suggestion: #5271
+    match mutv {
+        ref mut x @ _ => {
+            x.push(4);
+            println!("vec: {:?}", x);
+        },
+        ref y if y == &vec![0] => (),
+    }
+
+    match mutv {
+        ref x @ _ => println!("vec: {:?}", x),
+        ref y if y == &vec![0] => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/patterns.stderr b/src/tools/clippy/tests/ui/patterns.stderr
new file mode 100644
index 00000000000..af067580688
--- /dev/null
+++ b/src/tools/clippy/tests/ui/patterns.stderr
@@ -0,0 +1,22 @@
+error: the `y @ _` pattern can be written as just `y`
+  --> $DIR/patterns.rs:10:9
+   |
+LL |         y @ _ => (),
+   |         ^^^^^ help: try: `y`
+   |
+   = note: `-D clippy::redundant-pattern` implied by `-D warnings`
+
+error: the `x @ _` pattern can be written as just `x`
+  --> $DIR/patterns.rs:25:9
+   |
+LL |         ref mut x @ _ => {
+   |         ^^^^^^^^^^^^^ help: try: `ref mut x`
+
+error: the `x @ _` pattern can be written as just `x`
+  --> $DIR/patterns.rs:33:9
+   |
+LL |         ref x @ _ => println!("vec: {:?}", x),
+   |         ^^^^^^^^^ help: try: `ref x`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/precedence.fixed b/src/tools/clippy/tests/ui/precedence.fixed
new file mode 100644
index 00000000000..17b1f1bd0bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence.fixed
@@ -0,0 +1,53 @@
+// run-rustfix
+#![warn(clippy::precedence)]
+#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+macro_rules! trip {
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
+}
+
+fn main() {
+    1 << (2 + 3);
+    (1 + 2) << 3;
+    4 >> (1 + 1);
+    (1 + 3) >> 2;
+    1 ^ (1 - 1);
+    3 | (2 - 1);
+    3 & (5 - 2);
+    -(1i32.abs());
+    -(1f32.abs());
+
+    // These should not trigger an error
+    let _ = (-1i32).abs();
+    let _ = (-1f32).abs();
+    let _ = -(1i32).abs();
+    let _ = -(1f32).abs();
+    let _ = -(1i32.abs());
+    let _ = -(1f32.abs());
+
+    // Odd functions shoud not trigger an error
+    let _ = -1f64.asin();
+    let _ = -1f64.asinh();
+    let _ = -1f64.atan();
+    let _ = -1f64.atanh();
+    let _ = -1f64.cbrt();
+    let _ = -1f64.fract();
+    let _ = -1f64.round();
+    let _ = -1f64.signum();
+    let _ = -1f64.sin();
+    let _ = -1f64.sinh();
+    let _ = -1f64.tan();
+    let _ = -1f64.tanh();
+    let _ = -1f64.to_degrees();
+    let _ = -1f64.to_radians();
+
+    let b = 3;
+    trip!(b * 8);
+}
diff --git a/src/tools/clippy/tests/ui/precedence.rs b/src/tools/clippy/tests/ui/precedence.rs
new file mode 100644
index 00000000000..2d0891fd3c2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence.rs
@@ -0,0 +1,53 @@
+// run-rustfix
+#![warn(clippy::precedence)]
+#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+macro_rules! trip {
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
+}
+
+fn main() {
+    1 << 2 + 3;
+    1 + 2 << 3;
+    4 >> 1 + 1;
+    1 + 3 >> 2;
+    1 ^ 1 - 1;
+    3 | 2 - 1;
+    3 & 5 - 2;
+    -1i32.abs();
+    -1f32.abs();
+
+    // These should not trigger an error
+    let _ = (-1i32).abs();
+    let _ = (-1f32).abs();
+    let _ = -(1i32).abs();
+    let _ = -(1f32).abs();
+    let _ = -(1i32.abs());
+    let _ = -(1f32.abs());
+
+    // Odd functions shoud not trigger an error
+    let _ = -1f64.asin();
+    let _ = -1f64.asinh();
+    let _ = -1f64.atan();
+    let _ = -1f64.atanh();
+    let _ = -1f64.cbrt();
+    let _ = -1f64.fract();
+    let _ = -1f64.round();
+    let _ = -1f64.signum();
+    let _ = -1f64.sin();
+    let _ = -1f64.sinh();
+    let _ = -1f64.tan();
+    let _ = -1f64.tanh();
+    let _ = -1f64.to_degrees();
+    let _ = -1f64.to_radians();
+
+    let b = 3;
+    trip!(b * 8);
+}
diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr
new file mode 100644
index 00000000000..a2ed5392bfc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence.stderr
@@ -0,0 +1,58 @@
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:17:5
+   |
+LL |     1 << 2 + 3;
+   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)`
+   |
+   = note: `-D clippy::precedence` implied by `-D warnings`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:18:5
+   |
+LL |     1 + 2 << 3;
+   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:19:5
+   |
+LL |     4 >> 1 + 1;
+   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:20:5
+   |
+LL |     1 + 3 >> 2;
+   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:21:5
+   |
+LL |     1 ^ 1 - 1;
+   |     ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:22:5
+   |
+LL |     3 | 2 - 1;
+   |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)`
+
+error: operator precedence can trip the unwary
+  --> $DIR/precedence.rs:23:5
+   |
+LL |     3 & 5 - 2;
+   |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)`
+
+error: unary minus has lower precedence than method call
+  --> $DIR/precedence.rs:24:5
+   |
+LL |     -1i32.abs();
+   |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())`
+
+error: unary minus has lower precedence than method call
+  --> $DIR/precedence.rs:25:5
+   |
+LL |     -1f32.abs();
+   |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/print.rs b/src/tools/clippy/tests/ui/print.rs
new file mode 100644
index 00000000000..366ccc2b3bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print.rs
@@ -0,0 +1,35 @@
+#![allow(clippy::print_literal, clippy::write_literal)]
+#![warn(clippy::print_stdout, clippy::use_debug)]
+
+use std::fmt::{Debug, Display, Formatter, Result};
+
+#[allow(dead_code)]
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        write!(f, "{:?}", 43.1415)
+    }
+}
+
+impl Debug for Foo {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        // ok, we can use `Debug` formatting in `Debug` implementations
+        write!(f, "{:?}", 42.718)
+    }
+}
+
+fn main() {
+    println!("Hello");
+    print!("Hello");
+
+    print!("Hello {}", "World");
+
+    print!("Hello {:?}", "World");
+
+    print!("Hello {:#?}", "#orld");
+
+    assert_eq!(42, 1337);
+
+    vec![1, 2];
+}
diff --git a/src/tools/clippy/tests/ui/print.stderr b/src/tools/clippy/tests/ui/print.stderr
new file mode 100644
index 00000000000..208d9532628
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print.stderr
@@ -0,0 +1,54 @@
+error: use of `Debug`-based formatting
+  --> $DIR/print.rs:11:19
+   |
+LL |         write!(f, "{:?}", 43.1415)
+   |                   ^^^^^^
+   |
+   = note: `-D clippy::use-debug` implied by `-D warnings`
+
+error: use of `println!`
+  --> $DIR/print.rs:23:5
+   |
+LL |     println!("Hello");
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::print-stdout` implied by `-D warnings`
+
+error: use of `print!`
+  --> $DIR/print.rs:24:5
+   |
+LL |     print!("Hello");
+   |     ^^^^^^^^^^^^^^^
+
+error: use of `print!`
+  --> $DIR/print.rs:26:5
+   |
+LL |     print!("Hello {}", "World");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: use of `print!`
+  --> $DIR/print.rs:28:5
+   |
+LL |     print!("Hello {:?}", "World");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: use of `Debug`-based formatting
+  --> $DIR/print.rs:28:12
+   |
+LL |     print!("Hello {:?}", "World");
+   |            ^^^^^^^^^^^^
+
+error: use of `print!`
+  --> $DIR/print.rs:30:5
+   |
+LL |     print!("Hello {:#?}", "#orld");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: use of `Debug`-based formatting
+  --> $DIR/print.rs:30:12
+   |
+LL |     print!("Hello {:#?}", "#orld");
+   |            ^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
new file mode 100644
index 00000000000..40ed18e9302
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -0,0 +1,38 @@
+#![warn(clippy::print_literal)]
+
+fn main() {
+    // these should be fine
+    print!("Hello");
+    println!("Hello");
+    let world = "world";
+    println!("Hello {}", world);
+    println!("Hello {world}", world = world);
+    println!("3 in hex is {:X}", 3);
+    println!("2 + 1 = {:.4}", 3);
+    println!("2 + 1 = {:5.4}", 3);
+    println!("Debug test {:?}", "hello, world");
+    println!("{0:8} {1:>8}", "hello", "world");
+    println!("{1:8} {0:>8}", "hello", "world");
+    println!("{foo:8} {bar:>8}", foo = "hello", bar = "world");
+    println!("{bar:8} {foo:>8}", foo = "hello", bar = "world");
+    println!("{number:>width$}", number = 1, width = 6);
+    println!("{number:>0width$}", number = 1, width = 6);
+
+    // these should throw warnings
+    println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
+    print!("Hello {}", "world");
+    println!("Hello {} {}", world, "world");
+    println!("Hello {}", "world");
+    println!("10 / 4 is {}", 2.5);
+    println!("2 + 1 = {}", 3);
+
+    // positional args don't change the fact
+    // that we're using a literal -- this should
+    // throw a warning
+    println!("{0} {1}", "hello", "world");
+    println!("{1} {0}", "hello", "world");
+
+    // named args shouldn't change anything either
+    println!("{foo} {bar}", foo = "hello", bar = "world");
+    println!("{bar} {foo}", foo = "hello", bar = "world");
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
new file mode 100644
index 00000000000..fc502e9f71d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -0,0 +1,88 @@
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:22:71
+   |
+LL |     println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
+   |                                                                       ^
+   |
+   = note: `-D clippy::print-literal` implied by `-D warnings`
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:23:24
+   |
+LL |     print!("Hello {}", "world");
+   |                        ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:24:36
+   |
+LL |     println!("Hello {} {}", world, "world");
+   |                                    ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:25:26
+   |
+LL |     println!("Hello {}", "world");
+   |                          ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:26:30
+   |
+LL |     println!("10 / 4 is {}", 2.5);
+   |                              ^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:27:28
+   |
+LL |     println!("2 + 1 = {}", 3);
+   |                            ^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:32:25
+   |
+LL |     println!("{0} {1}", "hello", "world");
+   |                         ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:32:34
+   |
+LL |     println!("{0} {1}", "hello", "world");
+   |                                  ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:33:25
+   |
+LL |     println!("{1} {0}", "hello", "world");
+   |                         ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:33:34
+   |
+LL |     println!("{1} {0}", "hello", "world");
+   |                                  ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:36:35
+   |
+LL |     println!("{foo} {bar}", foo = "hello", bar = "world");
+   |                                   ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:36:50
+   |
+LL |     println!("{foo} {bar}", foo = "hello", bar = "world");
+   |                                                  ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:37:35
+   |
+LL |     println!("{bar} {foo}", foo = "hello", bar = "world");
+   |                                   ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/print_literal.rs:37:50
+   |
+LL |     println!("{bar} {foo}", foo = "hello", bar = "world");
+   |                                                  ^^^^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/print_with_newline.rs b/src/tools/clippy/tests/ui/print_with_newline.rs
new file mode 100644
index 00000000000..3f710540e90
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_with_newline.rs
@@ -0,0 +1,51 @@
+// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
+// // run-rustfix
+
+#![allow(clippy::print_literal)]
+#![warn(clippy::print_with_newline)]
+
+fn main() {
+    print!("Hello\n");
+    print!("Hello {}\n", "world");
+    print!("Hello {} {}\n", "world", "#2");
+    print!("{}\n", 1265);
+
+    // these are all fine
+    print!("");
+    print!("Hello");
+    println!("Hello");
+    println!("Hello\n");
+    println!("Hello {}\n", "world");
+    print!("Issue\n{}", 1265);
+    print!("{}", 1265);
+    print!("\n{}", 1275);
+    print!("\n\n");
+    print!("like eof\n\n");
+    print!("Hello {} {}\n\n", "world", "#2");
+    println!("\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
+    println!("\nbla\n\n"); // #3126
+
+    // Escaping
+    print!("\\n"); // #3514
+    print!("\\\n"); // should fail
+    print!("\\\\n");
+
+    // Raw strings
+    print!(r"\n"); // #3778
+
+    // Literal newlines should also fail
+    print!(
+        "
+"
+    );
+    print!(
+        r"
+"
+    );
+
+    // Don't warn on CRLF (#4208)
+    print!("\r\n");
+    print!("foo\r\n");
+    print!("\\r\n"); //~ ERROR
+    print!("foo\rbar\n") // ~ ERROR
+}
diff --git a/src/tools/clippy/tests/ui/print_with_newline.stderr b/src/tools/clippy/tests/ui/print_with_newline.stderr
new file mode 100644
index 00000000000..05fe88915d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_with_newline.stderr
@@ -0,0 +1,110 @@
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:8:5
+   |
+LL |     print!("Hello/n");
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::print-with-newline` implied by `-D warnings`
+help: use `println!` instead
+   |
+LL |     println!("Hello");
+   |     ^^^^^^^       --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:9:5
+   |
+LL |     print!("Hello {}/n", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("Hello {}", "world");
+   |     ^^^^^^^          --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:10:5
+   |
+LL |     print!("Hello {} {}/n", "world", "#2");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("Hello {} {}", "world", "#2");
+   |     ^^^^^^^             --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:11:5
+   |
+LL |     print!("{}/n", 1265);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("{}", 1265);
+   |     ^^^^^^^    --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:30:5
+   |
+LL |     print!("//n"); // should fail
+   |     ^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("/"); // should fail
+   |     ^^^^^^^    --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:37:5
+   |
+LL | /     print!(
+LL | |         "
+LL | | "
+LL | |     );
+   | |_____^
+   |
+help: use `println!` instead
+   |
+LL |     println!(
+LL |         ""
+   |
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:41:5
+   |
+LL | /     print!(
+LL | |         r"
+LL | | "
+LL | |     );
+   | |_____^
+   |
+help: use `println!` instead
+   |
+LL |     println!(
+LL |         r""
+   |
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:49:5
+   |
+LL |     print!("/r/n"); //~ ERROR
+   |     ^^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("/r"); //~ ERROR
+   |     ^^^^^^^     --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:50:5
+   |
+LL |     print!("foo/rbar/n") // ~ ERROR
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!("foo/rbar") // ~ ERROR
+   |     ^^^^^^^          --
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/println_empty_string.fixed b/src/tools/clippy/tests/ui/println_empty_string.fixed
new file mode 100644
index 00000000000..2b889b62ea9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/println_empty_string.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(clippy::match_single_binding)]
+
+fn main() {
+    println!();
+    println!();
+
+    match "a" {
+        _ => println!(),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/println_empty_string.rs b/src/tools/clippy/tests/ui/println_empty_string.rs
new file mode 100644
index 00000000000..890f5f68476
--- /dev/null
+++ b/src/tools/clippy/tests/ui/println_empty_string.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(clippy::match_single_binding)]
+
+fn main() {
+    println!();
+    println!("");
+
+    match "a" {
+        _ => println!(""),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/println_empty_string.stderr b/src/tools/clippy/tests/ui/println_empty_string.stderr
new file mode 100644
index 00000000000..23112b88168
--- /dev/null
+++ b/src/tools/clippy/tests/ui/println_empty_string.stderr
@@ -0,0 +1,16 @@
+error: using `println!("")`
+  --> $DIR/println_empty_string.rs:6:5
+   |
+LL |     println!("");
+   |     ^^^^^^^^^^^^ help: replace it with: `println!()`
+   |
+   = note: `-D clippy::println-empty-string` implied by `-D warnings`
+
+error: using `println!("")`
+  --> $DIR/println_empty_string.rs:9:14
+   |
+LL |         _ => println!(""),
+   |              ^^^^^^^^^^^^ help: replace it with: `println!()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/proc_macro.rs b/src/tools/clippy/tests/ui/proc_macro.rs
new file mode 100644
index 00000000000..59914b8b8f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/proc_macro.rs
@@ -0,0 +1,26 @@
+//! Check that we correctly lint procedural macros.
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[allow(dead_code)]
+fn f() {
+    let _x = 3.14;
+}
+
+#[proc_macro]
+pub fn mybangmacro(t: TokenStream) -> TokenStream {
+    t
+}
+
+#[proc_macro_derive(MyDerivedTrait)]
+pub fn myderive(t: TokenStream) -> TokenStream {
+    t
+}
+
+#[proc_macro_attribute]
+pub fn myattribute(t: TokenStream, a: TokenStream) -> TokenStream {
+    t
+}
diff --git a/src/tools/clippy/tests/ui/proc_macro.stderr b/src/tools/clippy/tests/ui/proc_macro.stderr
new file mode 100644
index 00000000000..872cbc66af6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/proc_macro.stderr
@@ -0,0 +1,10 @@
+error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
+  --> $DIR/proc_macro.rs:10:14
+   |
+LL |     let _x = 3.14;
+   |              ^^^^
+   |
+   = note: `#[deny(clippy::approx_constant)]` on by default
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
new file mode 100644
index 00000000000..30f39e9b063
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -0,0 +1,86 @@
+#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
+#![warn(clippy::ptr_arg)]
+
+use std::borrow::Cow;
+
+fn do_vec(x: &Vec<i64>) {
+    //Nothing here
+}
+
+fn do_vec_mut(x: &mut Vec<i64>) {
+    // no error here
+    //Nothing here
+}
+
+fn do_str(x: &String) {
+    //Nothing here either
+}
+
+fn do_str_mut(x: &mut String) {
+    // no error here
+    //Nothing here either
+}
+
+fn main() {}
+
+trait Foo {
+    type Item;
+    fn do_vec(x: &Vec<i64>);
+    fn do_item(x: &Self::Item);
+}
+
+struct Bar;
+
+// no error, in trait impl (#425)
+impl Foo for Bar {
+    type Item = Vec<u8>;
+    fn do_vec(x: &Vec<i64>) {}
+    fn do_item(x: &Vec<u8>) {}
+}
+
+fn cloned(x: &Vec<u8>) -> Vec<u8> {
+    let e = x.clone();
+    let f = e.clone(); // OK
+    let g = x;
+    let h = g.clone(); // Alas, we cannot reliably detect this without following data.
+    let i = (e).clone();
+    x.clone()
+}
+
+fn str_cloned(x: &String) -> String {
+    let a = x.clone();
+    let b = x.clone();
+    let c = b.clone();
+    let d = a.clone().clone().clone();
+    x.clone()
+}
+
+fn false_positive_capacity(x: &Vec<u8>, y: &String) {
+    let a = x.capacity();
+    let b = y.clone();
+    let c = y.as_str();
+}
+
+fn false_positive_capacity_too(x: &String) -> String {
+    if x.capacity() > 1024 {
+        panic!("Too large!");
+    }
+    x.clone()
+}
+
+#[allow(dead_code)]
+fn test_cow_with_ref(c: &Cow<[i32]>) {}
+
+#[allow(dead_code)]
+fn test_cow(c: Cow<[i32]>) {
+    let _c = c;
+}
+
+trait Foo2 {
+    fn do_string(&self);
+}
+
+// no error for &self references where self is of type String (#2293)
+impl Foo2 for String {
+    fn do_string(&self) {}
+}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
new file mode 100644
index 00000000000..314f23497f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -0,0 +1,89 @@
+error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
+  --> $DIR/ptr_arg.rs:6:14
+   |
+LL | fn do_vec(x: &Vec<i64>) {
+   |              ^^^^^^^^^ help: change this to: `&[i64]`
+   |
+   = note: `-D clippy::ptr-arg` implied by `-D warnings`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do.
+  --> $DIR/ptr_arg.rs:15:14
+   |
+LL | fn do_str(x: &String) {
+   |              ^^^^^^^ help: change this to: `&str`
+
+error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
+  --> $DIR/ptr_arg.rs:28:18
+   |
+LL |     fn do_vec(x: &Vec<i64>);
+   |                  ^^^^^^^^^ help: change this to: `&[i64]`
+
+error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
+  --> $DIR/ptr_arg.rs:41:14
+   |
+LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
+   |              ^^^^^^^^
+   |
+help: change this to
+   |
+LL | fn cloned(x: &[u8]) -> Vec<u8> {
+   |              ^^^^^
+help: change `x.clone()` to
+   |
+LL |     let e = x.to_owned();
+   |             ^^^^^^^^^^^^
+help: change `x.clone()` to
+   |
+LL |     x.to_owned()
+   |
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do.
+  --> $DIR/ptr_arg.rs:50:18
+   |
+LL | fn str_cloned(x: &String) -> String {
+   |                  ^^^^^^^
+   |
+help: change this to
+   |
+LL | fn str_cloned(x: &str) -> String {
+   |                  ^^^^
+help: change `x.clone()` to
+   |
+LL |     let a = x.to_string();
+   |             ^^^^^^^^^^^^^
+help: change `x.clone()` to
+   |
+LL |     let b = x.to_string();
+   |             ^^^^^^^^^^^^^
+help: change `x.clone()` to
+   |
+LL |     x.to_string()
+   |
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do.
+  --> $DIR/ptr_arg.rs:58:44
+   |
+LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
+   |                                            ^^^^^^^
+   |
+help: change this to
+   |
+LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
+   |                                            ^^^^
+help: change `y.clone()` to
+   |
+LL |     let b = y.to_string();
+   |             ^^^^^^^^^^^^^
+help: change `y.as_str()` to
+   |
+LL |     let c = y;
+   |             ^
+
+error: using a reference to `Cow` is not recommended.
+  --> $DIR/ptr_arg.rs:72:25
+   |
+LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
+   |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
new file mode 100644
index 00000000000..ebdd6c4003d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let vec = vec![b'a', b'b', b'c'];
+    let ptr = vec.as_ptr();
+
+    let offset_u8 = 1_u8;
+    let offset_usize = 1_usize;
+    let offset_isize = 1_isize;
+
+    unsafe {
+        ptr.add(offset_usize);
+        ptr.offset(offset_isize as isize);
+        ptr.offset(offset_u8 as isize);
+
+        ptr.wrapping_add(offset_usize);
+        ptr.wrapping_offset(offset_isize as isize);
+        ptr.wrapping_offset(offset_u8 as isize);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
new file mode 100644
index 00000000000..3416c4b727a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let vec = vec![b'a', b'b', b'c'];
+    let ptr = vec.as_ptr();
+
+    let offset_u8 = 1_u8;
+    let offset_usize = 1_usize;
+    let offset_isize = 1_isize;
+
+    unsafe {
+        ptr.offset(offset_usize as isize);
+        ptr.offset(offset_isize as isize);
+        ptr.offset(offset_u8 as isize);
+
+        ptr.wrapping_offset(offset_usize as isize);
+        ptr.wrapping_offset(offset_isize as isize);
+        ptr.wrapping_offset(offset_u8 as isize);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
new file mode 100644
index 00000000000..b5c7a03e277
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
@@ -0,0 +1,16 @@
+error: use of `offset` with a `usize` casted to an `isize`
+  --> $DIR/ptr_offset_with_cast.rs:12:9
+   |
+LL |         ptr.offset(offset_usize as isize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)`
+   |
+   = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings`
+
+error: use of `wrapping_offset` with a `usize` casted to an `isize`
+  --> $DIR/ptr_offset_with_cast.rs:16:9
+   |
+LL |         ptr.wrapping_offset(offset_usize as isize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
new file mode 100644
index 00000000000..11dff94a288
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -0,0 +1,125 @@
+// run-rustfix
+#![allow(unreachable_code)]
+
+fn some_func(a: Option<u32>) -> Option<u32> {
+    a?;
+
+    a
+}
+
+fn some_other_func(a: Option<u32>) -> Option<u32> {
+    if a.is_none() {
+        return None;
+    } else {
+        return Some(0);
+    }
+    unreachable!()
+}
+
+pub enum SeemsOption<T> {
+    Some(T),
+    None,
+}
+
+impl<T> SeemsOption<T> {
+    pub fn is_none(&self) -> bool {
+        match *self {
+            SeemsOption::None => true,
+            SeemsOption::Some(_) => false,
+        }
+    }
+}
+
+fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
+    if a.is_none() {
+        return SeemsOption::None;
+    }
+
+    a
+}
+
+pub struct CopyStruct {
+    pub opt: Option<u32>,
+}
+
+impl CopyStruct {
+    #[rustfmt::skip]
+    pub fn func(&self) -> Option<u32> {
+        (self.opt)?;
+
+        self.opt?;
+
+        let _ = Some(self.opt?);
+
+        let _ = self.opt?;
+
+        self.opt
+    }
+}
+
+#[derive(Clone)]
+pub struct MoveStruct {
+    pub opt: Option<Vec<u32>>,
+}
+
+impl MoveStruct {
+    pub fn ref_func(&self) -> Option<Vec<u32>> {
+        self.opt.as_ref()?;
+
+        self.opt.clone()
+    }
+
+    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
+        self.opt.as_ref()?;
+
+        self.opt
+    }
+
+    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
+        self.opt.as_ref()?;
+        Some(Vec::new())
+    }
+
+    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
+        let v: &Vec<_> = self.opt.as_ref()?;
+
+        Some(v.clone())
+    }
+
+    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
+        let v = self.opt?;
+
+        Some(v)
+    }
+}
+
+fn func() -> Option<i32> {
+    fn f() -> Option<String> {
+        Some(String::new())
+    }
+
+    f()?;
+
+    Some(0)
+}
+
+fn main() {
+    some_func(Some(42));
+    some_func(None);
+    some_other_func(Some(42));
+
+    let copy_struct = CopyStruct { opt: Some(54) };
+    copy_struct.func();
+
+    let move_struct = MoveStruct {
+        opt: Some(vec![42, 1337]),
+    };
+    move_struct.ref_func();
+    move_struct.clone().mov_func_reuse();
+    move_struct.mov_func_no_use();
+
+    let so = SeemsOption::Some(45);
+    returns_something_similar_to_option(so);
+
+    func();
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
new file mode 100644
index 00000000000..1d0ee82b4f7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -0,0 +1,155 @@
+// run-rustfix
+#![allow(unreachable_code)]
+
+fn some_func(a: Option<u32>) -> Option<u32> {
+    if a.is_none() {
+        return None;
+    }
+
+    a
+}
+
+fn some_other_func(a: Option<u32>) -> Option<u32> {
+    if a.is_none() {
+        return None;
+    } else {
+        return Some(0);
+    }
+    unreachable!()
+}
+
+pub enum SeemsOption<T> {
+    Some(T),
+    None,
+}
+
+impl<T> SeemsOption<T> {
+    pub fn is_none(&self) -> bool {
+        match *self {
+            SeemsOption::None => true,
+            SeemsOption::Some(_) => false,
+        }
+    }
+}
+
+fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
+    if a.is_none() {
+        return SeemsOption::None;
+    }
+
+    a
+}
+
+pub struct CopyStruct {
+    pub opt: Option<u32>,
+}
+
+impl CopyStruct {
+    #[rustfmt::skip]
+    pub fn func(&self) -> Option<u32> {
+        if (self.opt).is_none() {
+            return None;
+        }
+
+        if self.opt.is_none() {
+            return None
+        }
+
+        let _ = if self.opt.is_none() {
+            return None;
+        } else {
+            self.opt
+        };
+
+        let _ = if let Some(x) = self.opt {
+            x
+        } else {
+            return None;
+        };
+
+        self.opt
+    }
+}
+
+#[derive(Clone)]
+pub struct MoveStruct {
+    pub opt: Option<Vec<u32>>,
+}
+
+impl MoveStruct {
+    pub fn ref_func(&self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+
+        self.opt.clone()
+    }
+
+    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+
+        self.opt
+    }
+
+    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+        Some(Vec::new())
+    }
+
+    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
+        let v: &Vec<_> = if let Some(ref v) = self.opt {
+            v
+        } else {
+            return None;
+        };
+
+        Some(v.clone())
+    }
+
+    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
+        let v = if let Some(v) = self.opt {
+            v
+        } else {
+            return None;
+        };
+
+        Some(v)
+    }
+}
+
+fn func() -> Option<i32> {
+    fn f() -> Option<String> {
+        Some(String::new())
+    }
+
+    if f().is_none() {
+        return None;
+    }
+
+    Some(0)
+}
+
+fn main() {
+    some_func(Some(42));
+    some_func(None);
+    some_other_func(Some(42));
+
+    let copy_struct = CopyStruct { opt: Some(54) };
+    copy_struct.func();
+
+    let move_struct = MoveStruct {
+        opt: Some(vec![42, 1337]),
+    };
+    move_struct.ref_func();
+    move_struct.clone().mov_func_reuse();
+    move_struct.mov_func_no_use();
+
+    let so = SeemsOption::Some(45);
+    returns_something_similar_to_option(so);
+
+    func();
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
new file mode 100644
index 00000000000..502615fb175
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -0,0 +1,104 @@
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:5:5
+   |
+LL | /     if a.is_none() {
+LL | |         return None;
+LL | |     }
+   | |_____^ help: replace it with: `a?;`
+   |
+   = note: `-D clippy::question-mark` implied by `-D warnings`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:50:9
+   |
+LL | /         if (self.opt).is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace it with: `(self.opt)?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:54:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None
+LL | |         }
+   | |_________^ help: replace it with: `self.opt?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:58:17
+   |
+LL |           let _ = if self.opt.is_none() {
+   |  _________________^
+LL | |             return None;
+LL | |         } else {
+LL | |             self.opt
+LL | |         };
+   | |_________^ help: replace it with: `Some(self.opt?)`
+
+error: this if-let-else may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:64:17
+   |
+LL |           let _ = if let Some(x) = self.opt {
+   |  _________________^
+LL | |             x
+LL | |         } else {
+LL | |             return None;
+LL | |         };
+   | |_________^ help: replace it with: `self.opt?`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:81:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace it with: `self.opt.as_ref()?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:89:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace it with: `self.opt.as_ref()?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:97:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace it with: `self.opt.as_ref()?;`
+
+error: this if-let-else may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:104:26
+   |
+LL |           let v: &Vec<_> = if let Some(ref v) = self.opt {
+   |  __________________________^
+LL | |             v
+LL | |         } else {
+LL | |             return None;
+LL | |         };
+   | |_________^ help: replace it with: `self.opt.as_ref()?`
+
+error: this if-let-else may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:114:17
+   |
+LL |           let v = if let Some(v) = self.opt {
+   |  _________________^
+LL | |             v
+LL | |         } else {
+LL | |             return None;
+LL | |         };
+   | |_________^ help: replace it with: `self.opt?`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:129:5
+   |
+LL | /     if f().is_none() {
+LL | |         return None;
+LL | |     }
+   | |_____^ help: replace it with: `f()?;`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/range.rs b/src/tools/clippy/tests/ui/range.rs
new file mode 100644
index 00000000000..628282509c1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/range.rs
@@ -0,0 +1,16 @@
+#[warn(clippy::range_zip_with_len)]
+fn main() {
+    let v1 = vec![1, 2, 3];
+    let v2 = vec![4, 5];
+    let _x = v1.iter().zip(0..v1.len());
+    let _y = v1.iter().zip(0..v2.len()); // No error
+}
+
+#[allow(unused)]
+fn no_panic_with_fake_range_types() {
+    struct Range {
+        foo: i32,
+    }
+
+    let _ = Range { foo: 0 };
+}
diff --git a/src/tools/clippy/tests/ui/range.stderr b/src/tools/clippy/tests/ui/range.stderr
new file mode 100644
index 00000000000..d53c1edecac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/range.stderr
@@ -0,0 +1,10 @@
+error: It is more idiomatic to use `v1.iter().enumerate()`
+  --> $DIR/range.rs:5:14
+   |
+LL |     let _x = v1.iter().zip(0..v1.len());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::range-zip-with-len` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
new file mode 100644
index 00000000000..6b402114099
--- /dev/null
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
@@ -0,0 +1,41 @@
+// run-rustfix
+
+#![allow(unused_parens)]
+
+fn f() -> usize {
+    42
+}
+
+#[warn(clippy::range_plus_one)]
+fn main() {
+    for _ in 0..2 {}
+    for _ in 0..=2 {}
+
+    for _ in 0..=3 {}
+    for _ in 0..=3 + 1 {}
+
+    for _ in 0..=5 {}
+    for _ in 0..=1 + 5 {}
+
+    for _ in 1..=1 {}
+    for _ in 1..=1 + 1 {}
+
+    for _ in 0..13 + 13 {}
+    for _ in 0..=13 - 7 {}
+
+    for _ in 0..=f() {}
+    for _ in 0..=(1 + f()) {}
+
+    let _ = ..11 - 1;
+    let _ = ..11;
+    let _ = ..11;
+    let _ = (1..=11);
+    let _ = ((f() + 1)..=f());
+
+    const ONE: usize = 1;
+    // integer consts are linted, too
+    for _ in 1..=ONE {}
+
+    let mut vec: Vec<()> = std::vec::Vec::new();
+    vec.drain(..);
+}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
new file mode 100644
index 00000000000..3cfed4125b3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
@@ -0,0 +1,41 @@
+// run-rustfix
+
+#![allow(unused_parens)]
+
+fn f() -> usize {
+    42
+}
+
+#[warn(clippy::range_plus_one)]
+fn main() {
+    for _ in 0..2 {}
+    for _ in 0..=2 {}
+
+    for _ in 0..3 + 1 {}
+    for _ in 0..=3 + 1 {}
+
+    for _ in 0..1 + 5 {}
+    for _ in 0..=1 + 5 {}
+
+    for _ in 1..1 + 1 {}
+    for _ in 1..=1 + 1 {}
+
+    for _ in 0..13 + 13 {}
+    for _ in 0..=13 - 7 {}
+
+    for _ in 0..(1 + f()) {}
+    for _ in 0..=(1 + f()) {}
+
+    let _ = ..11 - 1;
+    let _ = ..=11 - 1;
+    let _ = ..=(11 - 1);
+    let _ = (1..11 + 1);
+    let _ = (f() + 1)..(f() + 1);
+
+    const ONE: usize = 1;
+    // integer consts are linted, too
+    for _ in 1..ONE + ONE {}
+
+    let mut vec: Vec<()> = std::vec::Vec::new();
+    vec.drain(..);
+}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
new file mode 100644
index 00000000000..f72943a04f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
@@ -0,0 +1,60 @@
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:14:14
+   |
+LL |     for _ in 0..3 + 1 {}
+   |              ^^^^^^^^ help: use: `0..=3`
+   |
+   = note: `-D clippy::range-plus-one` implied by `-D warnings`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:17:14
+   |
+LL |     for _ in 0..1 + 5 {}
+   |              ^^^^^^^^ help: use: `0..=5`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:20:14
+   |
+LL |     for _ in 1..1 + 1 {}
+   |              ^^^^^^^^ help: use: `1..=1`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:26:14
+   |
+LL |     for _ in 0..(1 + f()) {}
+   |              ^^^^^^^^^^^^ help: use: `0..=f()`
+
+error: an exclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:30:13
+   |
+LL |     let _ = ..=11 - 1;
+   |             ^^^^^^^^^ help: use: `..11`
+   |
+   = note: `-D clippy::range-minus-one` implied by `-D warnings`
+
+error: an exclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:31:13
+   |
+LL |     let _ = ..=(11 - 1);
+   |             ^^^^^^^^^^^ help: use: `..11`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:32:13
+   |
+LL |     let _ = (1..11 + 1);
+   |             ^^^^^^^^^^^ help: use: `(1..=11)`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:33:13
+   |
+LL |     let _ = (f() + 1)..(f() + 1);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:37:14
+   |
+LL |     for _ in 1..ONE + ONE {}
+   |              ^^^^^^^^^^^^ help: use: `1..=ONE`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.fixed b/src/tools/clippy/tests/ui/redundant_allocation.fixed
new file mode 100644
index 00000000000..26635833458
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_allocation.fixed
@@ -0,0 +1,48 @@
+// run-rustfix
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+
+use std::boxed::Box;
+use std::rc::Rc;
+
+pub struct MyStruct {}
+
+pub struct SubT<T> {
+    foo: T,
+}
+
+pub enum MyEnum {
+    One,
+    Two,
+}
+
+// Rc<&T>
+
+pub fn test1<T>(foo: &T) {}
+
+pub fn test2(foo: &MyStruct) {}
+
+pub fn test3(foo: &MyEnum) {}
+
+pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
+
+// Rc<Rc<T>>
+
+pub fn test5(a: Rc<bool>) {}
+
+// Rc<Box<T>>
+
+pub fn test6(a: Box<bool>) {}
+
+// Box<&T>
+
+pub fn test7<T>(foo: &T) {}
+
+pub fn test8(foo: &MyStruct) {}
+
+pub fn test9(foo: &MyEnum) {}
+
+pub fn test10_neg(foo: Box<SubT<&usize>>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
new file mode 100644
index 00000000000..677b3e56d4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -0,0 +1,48 @@
+// run-rustfix
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+
+use std::boxed::Box;
+use std::rc::Rc;
+
+pub struct MyStruct {}
+
+pub struct SubT<T> {
+    foo: T,
+}
+
+pub enum MyEnum {
+    One,
+    Two,
+}
+
+// Rc<&T>
+
+pub fn test1<T>(foo: Rc<&T>) {}
+
+pub fn test2(foo: Rc<&MyStruct>) {}
+
+pub fn test3(foo: Rc<&MyEnum>) {}
+
+pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
+
+// Rc<Rc<T>>
+
+pub fn test5(a: Rc<Rc<bool>>) {}
+
+// Rc<Box<T>>
+
+pub fn test6(a: Rc<Box<bool>>) {}
+
+// Box<&T>
+
+pub fn test7<T>(foo: Box<&T>) {}
+
+pub fn test8(foo: Box<&MyStruct>) {}
+
+pub fn test9(foo: Box<&MyEnum>) {}
+
+pub fn test10_neg(foo: Box<SubT<&usize>>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
new file mode 100644
index 00000000000..eaa57ce3024
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -0,0 +1,52 @@
+error: usage of `Rc<&T>`
+  --> $DIR/redundant_allocation.rs:22:22
+   |
+LL | pub fn test1<T>(foo: Rc<&T>) {}
+   |                      ^^^^^^ help: try: `&T`
+   |
+   = note: `-D clippy::redundant-allocation` implied by `-D warnings`
+
+error: usage of `Rc<&T>`
+  --> $DIR/redundant_allocation.rs:24:19
+   |
+LL | pub fn test2(foo: Rc<&MyStruct>) {}
+   |                   ^^^^^^^^^^^^^ help: try: `&MyStruct`
+
+error: usage of `Rc<&T>`
+  --> $DIR/redundant_allocation.rs:26:19
+   |
+LL | pub fn test3(foo: Rc<&MyEnum>) {}
+   |                   ^^^^^^^^^^^ help: try: `&MyEnum`
+
+error: usage of `Rc<Rc<T>>`
+  --> $DIR/redundant_allocation.rs:32:17
+   |
+LL | pub fn test5(a: Rc<Rc<bool>>) {}
+   |                 ^^^^^^^^^^^^ help: try: `Rc<bool>`
+
+error: usage of `Rc<Box<T>>`
+  --> $DIR/redundant_allocation.rs:36:17
+   |
+LL | pub fn test6(a: Rc<Box<bool>>) {}
+   |                 ^^^^^^^^^^^^^ help: try: `Box<bool>`
+
+error: usage of `Box<&T>`
+  --> $DIR/redundant_allocation.rs:40:22
+   |
+LL | pub fn test7<T>(foo: Box<&T>) {}
+   |                      ^^^^^^^ help: try: `&T`
+
+error: usage of `Box<&T>`
+  --> $DIR/redundant_allocation.rs:42:19
+   |
+LL | pub fn test8(foo: Box<&MyStruct>) {}
+   |                   ^^^^^^^^^^^^^^ help: try: `&MyStruct`
+
+error: usage of `Box<&T>`
+  --> $DIR/redundant_allocation.rs:44:19
+   |
+LL | pub fn test9(foo: Box<&MyEnum>) {}
+   |                   ^^^^^^^^^^^^ help: try: `&MyEnum`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
new file mode 100644
index 00000000000..764c10a6d39
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -0,0 +1,172 @@
+// run-rustfix
+// rustfix-only-machine-applicable
+
+use std::ffi::OsString;
+use std::path::Path;
+
+fn main() {
+    let _s = ["lorem", "ipsum"].join(" ");
+
+    let s = String::from("foo");
+    let _s = s;
+
+    let s = String::from("foo");
+    let _s = s;
+
+    let s = String::from("foo");
+    let _s = s;
+
+    let _s = Path::new("/a/b/").join("c");
+
+    let _s = Path::new("/a/b/").join("c");
+
+    let _s = OsString::new();
+
+    let _s = OsString::new();
+
+    // Check that lint level works
+    #[allow(clippy::redundant_clone)]
+    let _s = String::new().to_string();
+
+    let tup = (String::from("foo"),);
+    let _t = tup.0;
+
+    let tup_ref = &(String::from("foo"),);
+    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
+
+    {
+        let x = String::new();
+        let y = &x;
+
+        let _x = x.clone(); // ok; `x` is borrowed by `y`
+
+        let _ = y.len();
+    }
+
+    let x = (String::new(),);
+    let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x`
+
+    with_branch(Alpha, true);
+    cannot_double_move(Alpha);
+    cannot_move_from_type_with_drop();
+    borrower_propagation();
+    not_consumed();
+    issue_5405();
+}
+
+#[derive(Clone)]
+struct Alpha;
+fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
+    if b {
+        (a.clone(), a)
+    } else {
+        (Alpha, a)
+    }
+}
+
+fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) {
+    (a.clone(), a)
+}
+
+struct TypeWithDrop {
+    x: String,
+}
+
+impl Drop for TypeWithDrop {
+    fn drop(&mut self) {}
+}
+
+fn cannot_move_from_type_with_drop() -> String {
+    let s = TypeWithDrop { x: String::new() };
+    s.x.clone() // removing this `clone()` summons E0509
+}
+
+fn borrower_propagation() {
+    let s = String::new();
+    let t = String::new();
+
+    {
+        fn b() -> bool {
+            unimplemented!()
+        }
+        let _u = if b() { &s } else { &t };
+
+        // ok; `s` and `t` are possibly borrowed
+        let _s = s.clone();
+        let _t = t.clone();
+    }
+
+    {
+        let _u = || s.len();
+        let _v = [&t; 32];
+        let _s = s.clone(); // ok
+        let _t = t.clone(); // ok
+    }
+
+    {
+        let _u = {
+            let u = Some(&s);
+            let _ = s.clone(); // ok
+            u
+        };
+        let _s = s.clone(); // ok
+    }
+
+    {
+        use std::convert::identity as id;
+        let _u = id(id(&s));
+        let _s = s.clone(); // ok, `u` borrows `s`
+    }
+
+    let _s = s;
+    let _t = t;
+
+    #[derive(Clone)]
+    struct Foo {
+        x: usize,
+    }
+
+    {
+        let f = Foo { x: 123 };
+        let _x = Some(f.x);
+        let _f = f;
+    }
+
+    {
+        let f = Foo { x: 123 };
+        let _x = &f.x;
+        let _f = f.clone(); // ok
+    }
+}
+
+fn not_consumed() {
+    let x = std::path::PathBuf::from("home");
+    let y = x.join("matthias");
+    // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is
+    // redundant. (It also does not consume the PathBuf)
+
+    println!("x: {:?}, y: {:?}", x, y);
+
+    let mut s = String::new();
+    s.clone().push_str("foo"); // OK, removing this `clone()` will change the behavior.
+    s.push_str("bar");
+    assert_eq!(s, "bar");
+
+    let t = Some(s);
+    // OK
+    if let Some(x) = t.clone() {
+        println!("{}", x);
+    }
+    if let Some(x) = t {
+        println!("{}", x);
+    }
+}
+
+#[allow(clippy::clone_on_copy)]
+fn issue_5405() {
+    let a: [String; 1] = [String::from("foo")];
+    let _b: String = a[0].clone();
+
+    let c: [usize; 2] = [2, 3];
+    let _d: usize = c[1].clone();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
new file mode 100644
index 00000000000..839747b131d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -0,0 +1,172 @@
+// run-rustfix
+// rustfix-only-machine-applicable
+
+use std::ffi::OsString;
+use std::path::Path;
+
+fn main() {
+    let _s = ["lorem", "ipsum"].join(" ").to_string();
+
+    let s = String::from("foo");
+    let _s = s.clone();
+
+    let s = String::from("foo");
+    let _s = s.to_string();
+
+    let s = String::from("foo");
+    let _s = s.to_owned();
+
+    let _s = Path::new("/a/b/").join("c").to_owned();
+
+    let _s = Path::new("/a/b/").join("c").to_path_buf();
+
+    let _s = OsString::new().to_owned();
+
+    let _s = OsString::new().to_os_string();
+
+    // Check that lint level works
+    #[allow(clippy::redundant_clone)]
+    let _s = String::new().to_string();
+
+    let tup = (String::from("foo"),);
+    let _t = tup.0.clone();
+
+    let tup_ref = &(String::from("foo"),);
+    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
+
+    {
+        let x = String::new();
+        let y = &x;
+
+        let _x = x.clone(); // ok; `x` is borrowed by `y`
+
+        let _ = y.len();
+    }
+
+    let x = (String::new(),);
+    let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x`
+
+    with_branch(Alpha, true);
+    cannot_double_move(Alpha);
+    cannot_move_from_type_with_drop();
+    borrower_propagation();
+    not_consumed();
+    issue_5405();
+}
+
+#[derive(Clone)]
+struct Alpha;
+fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
+    if b {
+        (a.clone(), a.clone())
+    } else {
+        (Alpha, a)
+    }
+}
+
+fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) {
+    (a.clone(), a)
+}
+
+struct TypeWithDrop {
+    x: String,
+}
+
+impl Drop for TypeWithDrop {
+    fn drop(&mut self) {}
+}
+
+fn cannot_move_from_type_with_drop() -> String {
+    let s = TypeWithDrop { x: String::new() };
+    s.x.clone() // removing this `clone()` summons E0509
+}
+
+fn borrower_propagation() {
+    let s = String::new();
+    let t = String::new();
+
+    {
+        fn b() -> bool {
+            unimplemented!()
+        }
+        let _u = if b() { &s } else { &t };
+
+        // ok; `s` and `t` are possibly borrowed
+        let _s = s.clone();
+        let _t = t.clone();
+    }
+
+    {
+        let _u = || s.len();
+        let _v = [&t; 32];
+        let _s = s.clone(); // ok
+        let _t = t.clone(); // ok
+    }
+
+    {
+        let _u = {
+            let u = Some(&s);
+            let _ = s.clone(); // ok
+            u
+        };
+        let _s = s.clone(); // ok
+    }
+
+    {
+        use std::convert::identity as id;
+        let _u = id(id(&s));
+        let _s = s.clone(); // ok, `u` borrows `s`
+    }
+
+    let _s = s.clone();
+    let _t = t.clone();
+
+    #[derive(Clone)]
+    struct Foo {
+        x: usize,
+    }
+
+    {
+        let f = Foo { x: 123 };
+        let _x = Some(f.x);
+        let _f = f.clone();
+    }
+
+    {
+        let f = Foo { x: 123 };
+        let _x = &f.x;
+        let _f = f.clone(); // ok
+    }
+}
+
+fn not_consumed() {
+    let x = std::path::PathBuf::from("home");
+    let y = x.clone().join("matthias");
+    // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is
+    // redundant. (It also does not consume the PathBuf)
+
+    println!("x: {:?}, y: {:?}", x, y);
+
+    let mut s = String::new();
+    s.clone().push_str("foo"); // OK, removing this `clone()` will change the behavior.
+    s.push_str("bar");
+    assert_eq!(s, "bar");
+
+    let t = Some(s);
+    // OK
+    if let Some(x) = t.clone() {
+        println!("{}", x);
+    }
+    if let Some(x) = t {
+        println!("{}", x);
+    }
+}
+
+#[allow(clippy::clone_on_copy)]
+fn issue_5405() {
+    let a: [String; 1] = [String::from("foo")];
+    let _b: String = a[0].clone();
+
+    let c: [usize; 2] = [2, 3];
+    let _d: usize = c[1].clone();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
new file mode 100644
index 00000000000..eced198283c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -0,0 +1,171 @@
+error: redundant clone
+  --> $DIR/redundant_clone.rs:8:42
+   |
+LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
+   |                                          ^^^^^^^^^^^^ help: remove this
+   |
+   = note: `-D clippy::redundant-clone` implied by `-D warnings`
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:8:14
+   |
+LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:11:15
+   |
+LL |     let _s = s.clone();
+   |               ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:11:14
+   |
+LL |     let _s = s.clone();
+   |              ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:14:15
+   |
+LL |     let _s = s.to_string();
+   |               ^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:14:14
+   |
+LL |     let _s = s.to_string();
+   |              ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:17:15
+   |
+LL |     let _s = s.to_owned();
+   |               ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:17:14
+   |
+LL |     let _s = s.to_owned();
+   |              ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:19:42
+   |
+LL |     let _s = Path::new("/a/b/").join("c").to_owned();
+   |                                          ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:19:14
+   |
+LL |     let _s = Path::new("/a/b/").join("c").to_owned();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:21:42
+   |
+LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
+   |                                          ^^^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:21:14
+   |
+LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:23:29
+   |
+LL |     let _s = OsString::new().to_owned();
+   |                             ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:23:14
+   |
+LL |     let _s = OsString::new().to_owned();
+   |              ^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:25:29
+   |
+LL |     let _s = OsString::new().to_os_string();
+   |                             ^^^^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:25:14
+   |
+LL |     let _s = OsString::new().to_os_string();
+   |              ^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:32:19
+   |
+LL |     let _t = tup.0.clone();
+   |                   ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:32:14
+   |
+LL |     let _t = tup.0.clone();
+   |              ^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:61:22
+   |
+LL |         (a.clone(), a.clone())
+   |                      ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:61:21
+   |
+LL |         (a.clone(), a.clone())
+   |                     ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:121:15
+   |
+LL |     let _s = s.clone();
+   |               ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:121:14
+   |
+LL |     let _s = s.clone();
+   |              ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:122:15
+   |
+LL |     let _t = t.clone();
+   |               ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:122:14
+   |
+LL |     let _t = t.clone();
+   |              ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:132:19
+   |
+LL |         let _f = f.clone();
+   |                   ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:132:18
+   |
+LL |         let _f = f.clone();
+   |                  ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:144:14
+   |
+LL |     let y = x.clone().join("matthias");
+   |              ^^^^^^^^ help: remove this
+   |
+note: cloned value is neither consumed nor mutated
+  --> $DIR/redundant_clone.rs:144:13
+   |
+LL |     let y = x.clone().join("matthias");
+   |             ^^^^^^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call.rs b/src/tools/clippy/tests/ui/redundant_closure_call.rs
new file mode 100644
index 00000000000..bacd67db7c3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_closure_call.rs
@@ -0,0 +1,23 @@
+// non rustfixable, see redundant_closure_call_fixable.rs
+
+#![warn(clippy::redundant_closure_call)]
+
+fn main() {
+    let mut i = 1;
+    let mut k = (|m| m + 1)(i);
+
+    k = (|a, b| a * b)(1, 5);
+
+    let closure = || 32;
+    i = closure();
+
+    let closure = |i| i + 1;
+    i = closure(3);
+
+    i = closure(4);
+
+    #[allow(clippy::needless_return)]
+    (|| return 2)();
+    (|| -> Option<i32> { None? })();
+    (|| -> Result<i32, i32> { Err(2)? })();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call.stderr b/src/tools/clippy/tests/ui/redundant_closure_call.stderr
new file mode 100644
index 00000000000..68c1416bb6b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_closure_call.stderr
@@ -0,0 +1,28 @@
+error: Closure called just once immediately after it was declared
+  --> $DIR/redundant_closure_call.rs:12:5
+   |
+LL |     i = closure();
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
+
+error: Closure called just once immediately after it was declared
+  --> $DIR/redundant_closure_call.rs:15:5
+   |
+LL |     i = closure(3);
+   |     ^^^^^^^^^^^^^^
+
+error: Try not to call a closure in the expression where it is declared.
+  --> $DIR/redundant_closure_call.rs:7:17
+   |
+LL |     let mut k = (|m| m + 1)(i);
+   |                 ^^^^^^^^^^^^^^
+
+error: Try not to call a closure in the expression where it is declared.
+  --> $DIR/redundant_closure_call.rs:9:9
+   |
+LL |     k = (|a, b| a * b)(1, 5);
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
new file mode 100644
index 00000000000..0abca6fca06
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+
+#![warn(clippy::redundant_closure_call)]
+#![allow(unused)]
+
+fn main() {
+    let a = 42;
+}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
new file mode 100644
index 00000000000..f8b9d37a5cc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+
+#![warn(clippy::redundant_closure_call)]
+#![allow(unused)]
+
+fn main() {
+    let a = (|| 42)();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
new file mode 100644
index 00000000000..e7737f9dd85
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
@@ -0,0 +1,10 @@
+error: Try not to call a closure in the expression where it is declared.
+  --> $DIR/redundant_closure_call_fixable.rs:7:13
+   |
+LL |     let a = (|| 42)();
+   |             ^^^^^^^^^ help: Try doing something like: : `42`
+   |
+   = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed
new file mode 100644
index 00000000000..5b4b8eeedd4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed
@@ -0,0 +1,71 @@
+// run-rustfix
+#![warn(clippy::redundant_field_names)]
+#![allow(clippy::no_effect, dead_code, unused_variables)]
+
+#[macro_use]
+extern crate derive_new;
+
+use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
+
+mod foo {
+    pub const BAR: u8 = 0;
+}
+
+struct Person {
+    gender: u8,
+    age: u8,
+    name: u8,
+    buzz: u64,
+    foo: u8,
+}
+
+#[derive(new)]
+pub struct S {
+    v: String,
+}
+
+fn main() {
+    let gender: u8 = 42;
+    let age = 0;
+    let fizz: u64 = 0;
+    let name: u8 = 0;
+
+    let me = Person {
+        gender,
+        age,
+
+        name,          //should be ok
+        buzz: fizz,    //should be ok
+        foo: foo::BAR, //should be ok
+    };
+
+    // Range expressions
+    let (start, end) = (0, 0);
+
+    let _ = start..;
+    let _ = ..end;
+    let _ = start..end;
+
+    let _ = ..=end;
+    let _ = start..=end;
+
+    // Issue #2799
+    let _: Vec<_> = (start..end).collect();
+
+    // hand-written Range family structs are linted
+    let _ = RangeFrom { start };
+    let _ = RangeTo { end };
+    let _ = Range { start, end };
+    let _ = RangeInclusive::new(start, end);
+    let _ = RangeToInclusive { end };
+}
+
+fn issue_3476() {
+    fn foo<T>() {}
+
+    struct S {
+        foo: fn(),
+    }
+
+    S { foo: foo::<i32> };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs
new file mode 100644
index 00000000000..3f97b80c568
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_field_names.rs
@@ -0,0 +1,71 @@
+// run-rustfix
+#![warn(clippy::redundant_field_names)]
+#![allow(clippy::no_effect, dead_code, unused_variables)]
+
+#[macro_use]
+extern crate derive_new;
+
+use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
+
+mod foo {
+    pub const BAR: u8 = 0;
+}
+
+struct Person {
+    gender: u8,
+    age: u8,
+    name: u8,
+    buzz: u64,
+    foo: u8,
+}
+
+#[derive(new)]
+pub struct S {
+    v: String,
+}
+
+fn main() {
+    let gender: u8 = 42;
+    let age = 0;
+    let fizz: u64 = 0;
+    let name: u8 = 0;
+
+    let me = Person {
+        gender: gender,
+        age: age,
+
+        name,          //should be ok
+        buzz: fizz,    //should be ok
+        foo: foo::BAR, //should be ok
+    };
+
+    // Range expressions
+    let (start, end) = (0, 0);
+
+    let _ = start..;
+    let _ = ..end;
+    let _ = start..end;
+
+    let _ = ..=end;
+    let _ = start..=end;
+
+    // Issue #2799
+    let _: Vec<_> = (start..end).collect();
+
+    // hand-written Range family structs are linted
+    let _ = RangeFrom { start: start };
+    let _ = RangeTo { end: end };
+    let _ = Range { start: start, end: end };
+    let _ = RangeInclusive::new(start, end);
+    let _ = RangeToInclusive { end: end };
+}
+
+fn issue_3476() {
+    fn foo<T>() {}
+
+    struct S {
+        foo: fn(),
+    }
+
+    S { foo: foo::<i32> };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.stderr b/src/tools/clippy/tests/ui/redundant_field_names.stderr
new file mode 100644
index 00000000000..7976292df22
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_field_names.stderr
@@ -0,0 +1,46 @@
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:34:9
+   |
+LL |         gender: gender,
+   |         ^^^^^^^^^^^^^^ help: replace it with: `gender`
+   |
+   = note: `-D clippy::redundant-field-names` implied by `-D warnings`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:35:9
+   |
+LL |         age: age,
+   |         ^^^^^^^^ help: replace it with: `age`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:56:25
+   |
+LL |     let _ = RangeFrom { start: start };
+   |                         ^^^^^^^^^^^^ help: replace it with: `start`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:57:23
+   |
+LL |     let _ = RangeTo { end: end };
+   |                       ^^^^^^^^ help: replace it with: `end`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:58:21
+   |
+LL |     let _ = Range { start: start, end: end };
+   |                     ^^^^^^^^^^^^ help: replace it with: `start`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:58:35
+   |
+LL |     let _ = Range { start: start, end: end };
+   |                                   ^^^^^^^^ help: replace it with: `end`
+
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:60:32
+   |
+LL |     let _ = RangeToInclusive { end: end };
+   |                                ^^^^^^^^ help: replace it with: `end`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed
new file mode 100644
index 00000000000..fc8cb0e747c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.fixed
@@ -0,0 +1,119 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
+
+fn main() {
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    if None::<()>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    if Some(42).is_some() {
+        foo();
+    } else {
+        bar();
+    }
+
+    while Some(42).is_some() {}
+
+    while Some(42).is_none() {}
+
+    while None::<()>.is_none() {}
+
+    while Ok::<i32, i32>(10).is_ok() {}
+
+    while Ok::<i32, i32>(10).is_err() {}
+
+    let mut v = vec![1, 2, 3];
+    while v.pop().is_some() {
+        foo();
+    }
+
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    if None::<i32>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    if let Ok(x) = Ok::<i32, i32>(42) {
+        println!("{}", x);
+    }
+
+    Ok::<i32, i32>(42).is_ok();
+
+    Ok::<i32, i32>(42).is_err();
+
+    Err::<i32, i32>(42).is_err();
+
+    Err::<i32, i32>(42).is_ok();
+
+    Some(42).is_some();
+
+    None::<()>.is_none();
+
+    let _ = None::<()>.is_none();
+
+    let _ = if Ok::<usize, ()>(4).is_ok() { true } else { false };
+
+    let opt = Some(false);
+    let x = if opt.is_some() { true } else { false };
+    takes_bool(x);
+
+    issue5504();
+
+    let _ = if gen_opt().is_some() {
+        1
+    } else if gen_opt().is_none() {
+        2
+    } else if gen_res().is_ok() {
+        3
+    } else if gen_res().is_err() {
+        4
+    } else {
+        5
+    };
+}
+
+fn gen_opt() -> Option<()> {
+    None
+}
+
+fn gen_res() -> Result<(), ()> {
+    Ok(())
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+macro_rules! m {
+    () => {
+        Some(42u32)
+    };
+}
+
+fn issue5504() {
+    fn result_opt() -> Result<Option<i32>, i32> {
+        Err(42)
+    }
+
+    fn try_result_opt() -> Result<i32, i32> {
+        while r#try!(result_opt()).is_some() {}
+        if r#try!(result_opt()).is_some() {}
+        Ok(42)
+    }
+
+    try_result_opt();
+
+    if m!().is_some() {}
+    while m!().is_some() {}
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs
new file mode 100644
index 00000000000..51912dade03
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.rs
@@ -0,0 +1,140 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
+
+fn main() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let None = None::<()> {}
+
+    if let Some(_) = Some(42) {}
+
+    if let Some(_) = Some(42) {
+        foo();
+    } else {
+        bar();
+    }
+
+    while let Some(_) = Some(42) {}
+
+    while let None = Some(42) {}
+
+    while let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    let mut v = vec![1, 2, 3];
+    while let Some(_) = v.pop() {
+        foo();
+    }
+
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    if None::<i32>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    if let Ok(x) = Ok::<i32, i32>(42) {
+        println!("{}", x);
+    }
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+
+    let _ = match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+
+    let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
+
+    let opt = Some(false);
+    let x = if let Some(_) = opt { true } else { false };
+    takes_bool(x);
+
+    issue5504();
+
+    let _ = if let Some(_) = gen_opt() {
+        1
+    } else if let None = gen_opt() {
+        2
+    } else if let Ok(_) = gen_res() {
+        3
+    } else if let Err(_) = gen_res() {
+        4
+    } else {
+        5
+    };
+}
+
+fn gen_opt() -> Option<()> {
+    None
+}
+
+fn gen_res() -> Result<(), ()> {
+    Ok(())
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+macro_rules! m {
+    () => {
+        Some(42u32)
+    };
+}
+
+fn issue5504() {
+    fn result_opt() -> Result<Option<i32>, i32> {
+        Err(42)
+    }
+
+    fn try_result_opt() -> Result<i32, i32> {
+        while let Some(_) = r#try!(result_opt()) {}
+        if let Some(_) = r#try!(result_opt()) {}
+        Ok(42)
+    }
+
+    try_result_opt();
+
+    if let Some(_) = m!() {}
+    while let Some(_) = m!() {}
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr
new file mode 100644
index 00000000000..b58deb7954e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching.stderr
@@ -0,0 +1,194 @@
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:8:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:10:12
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:12:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:14:12
+   |
+LL |     if let Some(_) = Some(42) {}
+   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:16:12
+   |
+LL |     if let Some(_) = Some(42) {
+   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:22:15
+   |
+LL |     while let Some(_) = Some(42) {}
+   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:24:15
+   |
+LL |     while let None = Some(42) {}
+   |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:26:15
+   |
+LL |     while let None = None::<()> {}
+   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:28:15
+   |
+LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:30:15
+   |
+LL |     while let Err(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:33:15
+   |
+LL |     while let Some(_) = v.pop() {
+   |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:49:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:54:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:59:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:64:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:69:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => true,
+LL | |         None => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:74:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:79:13
+   |
+LL |       let _ = match None::<()> {
+   |  _____________^
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:84:20
+   |
+LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
+   |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:87:20
+   |
+LL |     let x = if let Some(_) = opt { true } else { false };
+   |             -------^^^^^^^------ help: try this: `if opt.is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:92:20
+   |
+LL |     let _ = if let Some(_) = gen_opt() {
+   |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:94:19
+   |
+LL |     } else if let None = gen_opt() {
+   |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:96:19
+   |
+LL |     } else if let Ok(_) = gen_res() {
+   |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:98:19
+   |
+LL |     } else if let Err(_) = gen_res() {
+   |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:131:19
+   |
+LL |         while let Some(_) = r#try!(result_opt()) {}
+   |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:132:16
+   |
+LL |         if let Some(_) = r#try!(result_opt()) {}
+   |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:138:12
+   |
+LL |     if let Some(_) = m!() {}
+   |     -------^^^^^^^------- help: try this: `if m!().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:139:15
+   |
+LL |     while let Some(_) = m!() {}
+   |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
+
+error: aborting due to 28 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed
new file mode 100644
index 00000000000..25f2fd061b8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed
@@ -0,0 +1,107 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::redundant_pub_crate)]
+
+mod m1 {
+    fn f() {}
+    pub fn g() {} // private due to m1
+    pub fn h() {}
+
+    mod m1_1 {
+        fn f() {}
+        pub fn g() {} // private due to m1_1 and m1
+        pub fn h() {}
+    }
+
+    pub mod m1_2 {
+        // ^ private due to m1
+        fn f() {}
+        pub fn g() {} // private due to m1_2 and m1
+        pub fn h() {}
+    }
+
+    pub mod m1_3 {
+        fn f() {}
+        pub fn g() {} // private due to m1
+        pub fn h() {}
+    }
+}
+
+pub(crate) mod m2 {
+    fn f() {}
+    pub fn g() {} // already crate visible due to m2
+    pub fn h() {}
+
+    mod m2_1 {
+        fn f() {}
+        pub fn g() {} // private due to m2_1
+        pub fn h() {}
+    }
+
+    pub mod m2_2 {
+        // ^ already crate visible due to m2
+        fn f() {}
+        pub fn g() {} // already crate visible due to m2_2 and m2
+        pub fn h() {}
+    }
+
+    pub mod m2_3 {
+        fn f() {}
+        pub fn g() {} // already crate visible due to m2
+        pub fn h() {}
+    }
+}
+
+pub mod m3 {
+    fn f() {}
+    pub(crate) fn g() {} // ok: m3 is exported
+    pub fn h() {}
+
+    mod m3_1 {
+        fn f() {}
+        pub fn g() {} // private due to m3_1
+        pub fn h() {}
+    }
+
+    pub(crate) mod m3_2 {
+        // ^ ok
+        fn f() {}
+        pub fn g() {} // already crate visible due to m3_2
+        pub fn h() {}
+    }
+
+    pub mod m3_3 {
+        fn f() {}
+        pub(crate) fn g() {} // ok: m3 and m3_3 are exported
+        pub fn h() {}
+    }
+}
+
+mod m4 {
+    fn f() {}
+    pub fn g() {} // private: not re-exported by `pub use m4::*`
+    pub fn h() {}
+
+    mod m4_1 {
+        fn f() {}
+        pub fn g() {} // private due to m4_1
+        pub fn h() {}
+    }
+
+    pub mod m4_2 {
+        // ^ private: not re-exported by `pub use m4::*`
+        fn f() {}
+        pub fn g() {} // private due to m4_2
+        pub fn h() {}
+    }
+
+    pub mod m4_3 {
+        fn f() {}
+        pub(crate) fn g() {} // ok: m4_3 is re-exported by `pub use m4::*`
+        pub fn h() {}
+    }
+}
+
+pub use m4::*;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.rs b/src/tools/clippy/tests/ui/redundant_pub_crate.rs
new file mode 100644
index 00000000000..616286b4f39
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.rs
@@ -0,0 +1,107 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::redundant_pub_crate)]
+
+mod m1 {
+    fn f() {}
+    pub(crate) fn g() {} // private due to m1
+    pub fn h() {}
+
+    mod m1_1 {
+        fn f() {}
+        pub(crate) fn g() {} // private due to m1_1 and m1
+        pub fn h() {}
+    }
+
+    pub(crate) mod m1_2 {
+        // ^ private due to m1
+        fn f() {}
+        pub(crate) fn g() {} // private due to m1_2 and m1
+        pub fn h() {}
+    }
+
+    pub mod m1_3 {
+        fn f() {}
+        pub(crate) fn g() {} // private due to m1
+        pub fn h() {}
+    }
+}
+
+pub(crate) mod m2 {
+    fn f() {}
+    pub(crate) fn g() {} // already crate visible due to m2
+    pub fn h() {}
+
+    mod m2_1 {
+        fn f() {}
+        pub(crate) fn g() {} // private due to m2_1
+        pub fn h() {}
+    }
+
+    pub(crate) mod m2_2 {
+        // ^ already crate visible due to m2
+        fn f() {}
+        pub(crate) fn g() {} // already crate visible due to m2_2 and m2
+        pub fn h() {}
+    }
+
+    pub mod m2_3 {
+        fn f() {}
+        pub(crate) fn g() {} // already crate visible due to m2
+        pub fn h() {}
+    }
+}
+
+pub mod m3 {
+    fn f() {}
+    pub(crate) fn g() {} // ok: m3 is exported
+    pub fn h() {}
+
+    mod m3_1 {
+        fn f() {}
+        pub(crate) fn g() {} // private due to m3_1
+        pub fn h() {}
+    }
+
+    pub(crate) mod m3_2 {
+        // ^ ok
+        fn f() {}
+        pub(crate) fn g() {} // already crate visible due to m3_2
+        pub fn h() {}
+    }
+
+    pub mod m3_3 {
+        fn f() {}
+        pub(crate) fn g() {} // ok: m3 and m3_3 are exported
+        pub fn h() {}
+    }
+}
+
+mod m4 {
+    fn f() {}
+    pub(crate) fn g() {} // private: not re-exported by `pub use m4::*`
+    pub fn h() {}
+
+    mod m4_1 {
+        fn f() {}
+        pub(crate) fn g() {} // private due to m4_1
+        pub fn h() {}
+    }
+
+    pub(crate) mod m4_2 {
+        // ^ private: not re-exported by `pub use m4::*`
+        fn f() {}
+        pub(crate) fn g() {} // private due to m4_2
+        pub fn h() {}
+    }
+
+    pub mod m4_3 {
+        fn f() {}
+        pub(crate) fn g() {} // ok: m4_3 is re-exported by `pub use m4::*`
+        pub fn h() {}
+    }
+}
+
+pub use m4::*;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr
new file mode 100644
index 00000000000..6fccdaa4e20
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr
@@ -0,0 +1,132 @@
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:7:5
+   |
+LL |     pub(crate) fn g() {} // private due to m1
+   |     ----------^^^^^
+   |     |
+   |     help: consider using: `pub`
+   |
+   = note: `-D clippy::redundant-pub-crate` implied by `-D warnings`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:12:9
+   |
+LL |         pub(crate) fn g() {} // private due to m1_1 and m1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) module inside private module
+  --> $DIR/redundant_pub_crate.rs:16:5
+   |
+LL |     pub(crate) mod m1_2 {
+   |     ----------^^^^^^^^^
+   |     |
+   |     help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:19:9
+   |
+LL |         pub(crate) fn g() {} // private due to m1_2 and m1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:25:9
+   |
+LL |         pub(crate) fn g() {} // private due to m1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:32:5
+   |
+LL |     pub(crate) fn g() {} // already crate visible due to m2
+   |     ----------^^^^^
+   |     |
+   |     help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:37:9
+   |
+LL |         pub(crate) fn g() {} // private due to m2_1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) module inside private module
+  --> $DIR/redundant_pub_crate.rs:41:5
+   |
+LL |     pub(crate) mod m2_2 {
+   |     ----------^^^^^^^^^
+   |     |
+   |     help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:44:9
+   |
+LL |         pub(crate) fn g() {} // already crate visible due to m2_2 and m2
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:50:9
+   |
+LL |         pub(crate) fn g() {} // already crate visible due to m2
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:62:9
+   |
+LL |         pub(crate) fn g() {} // private due to m3_1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:69:9
+   |
+LL |         pub(crate) fn g() {} // already crate visible due to m3_2
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:82:5
+   |
+LL |     pub(crate) fn g() {} // private: not re-exported by `pub use m4::*`
+   |     ----------^^^^^
+   |     |
+   |     help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:87:9
+   |
+LL |         pub(crate) fn g() {} // private due to m4_1
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: pub(crate) module inside private module
+  --> $DIR/redundant_pub_crate.rs:91:5
+   |
+LL |     pub(crate) mod m4_2 {
+   |     ----------^^^^^^^^^
+   |     |
+   |     help: consider using: `pub`
+
+error: pub(crate) function inside private module
+  --> $DIR/redundant_pub_crate.rs:94:9
+   |
+LL |         pub(crate) fn g() {} // private due to m4_2
+   |         ----------^^^^^
+   |         |
+   |         help: consider using: `pub`
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
new file mode 100644
index 00000000000..921249606ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
@@ -0,0 +1,56 @@
+// run-rustfix
+
+#![allow(unused)]
+
+#[derive(Debug)]
+struct Foo {}
+
+const VAR_ONE: &str = "Test constant #1"; // ERROR Consider removing 'static.
+
+const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
+
+const VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
+
+const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+
+const VAR_SIX: &u8 = &5;
+
+const VAR_HEIGHT: &Foo = &Foo {};
+
+const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR Consider removing 'static.
+
+const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+
+const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
+
+static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
+
+static STATIC_VAR_SIX: &u8 = &5;
+
+static STATIC_VAR_HEIGHT: &Foo = &Foo {};
+
+static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+
+static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
+
+fn main() {
+    let false_positive: &'static str = "test";
+}
+
+trait Bar {
+    const TRAIT_VAR: &'static str;
+}
+
+impl Foo {
+    const IMPL_VAR: &'static str = "var";
+}
+
+impl Bar for Foo {
+    const TRAIT_VAR: &'static str = "foo";
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
new file mode 100644
index 00000000000..4d4b249d076
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
@@ -0,0 +1,56 @@
+// run-rustfix
+
+#![allow(unused)]
+
+#[derive(Debug)]
+struct Foo {}
+
+const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
+
+const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
+
+const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+
+const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+
+const VAR_SIX: &'static u8 = &5;
+
+const VAR_HEIGHT: &'static Foo = &Foo {};
+
+const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
+
+const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+
+const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
+
+static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+
+static STATIC_VAR_SIX: &'static u8 = &5;
+
+static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
+
+static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
+
+static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+
+static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+
+fn main() {
+    let false_positive: &'static str = "test";
+}
+
+trait Bar {
+    const TRAIT_VAR: &'static str;
+}
+
+impl Foo {
+    const IMPL_VAR: &'static str = "var";
+}
+
+impl Bar for Foo {
+    const TRAIT_VAR: &'static str = "foo";
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
new file mode 100644
index 00000000000..3c3d2eacd8d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
@@ -0,0 +1,100 @@
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:8:17
+   |
+LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
+   |                -^^^^^^^---- help: consider removing `'static`: `&str`
+   |
+   = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:12:21
+   |
+LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+   |                    -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:14:32
+   |
+LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                               -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:14:47
+   |
+LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:16:17
+   |
+LL | const VAR_SIX: &'static u8 = &5;
+   |                -^^^^^^^--- help: consider removing `'static`: `&u8`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:18:20
+   |
+LL | const VAR_HEIGHT: &'static Foo = &Foo {};
+   |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:20:19
+   |
+LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
+   |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:22:19
+   |
+LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+   |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:24:19
+   |
+LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+   |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:26:25
+   |
+LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
+   |                        -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:30:29
+   |
+LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+   |                            -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:32:25
+   |
+LL | static STATIC_VAR_SIX: &'static u8 = &5;
+   |                        -^^^^^^^--- help: consider removing `'static`: `&u8`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:34:28
+   |
+LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
+   |                           -^^^^^^^---- help: consider removing `'static`: `&Foo`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:36:27
+   |
+LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
+   |                          -^^^^^^^----- help: consider removing `'static`: `&[u8]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:38:27
+   |
+LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+   |                          -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:40:27
+   |
+LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+   |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs
new file mode 100644
index 00000000000..f57dd58e230
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs
@@ -0,0 +1,13 @@
+// these are rustfixable, but run-rustfix tests cannot handle them
+
+const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+
+const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+
+static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+
+static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+
+static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr
new file mode 100644
index 00000000000..afc853dcfce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr
@@ -0,0 +1,64 @@
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:3:18
+   |
+LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                 -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
+   |
+   = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:3:30
+   |
+LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                             -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:5:29
+   |
+LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                            -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
+
+error: Constants have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:5:39
+   |
+LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                                      -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:7:40
+   |
+LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                                       -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:7:55
+   |
+LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                                                      -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:9:26
+   |
+LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                         -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:9:38
+   |
+LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                                     -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:11:37
+   |
+LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                                    -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes_multiple.rs:11:47
+   |
+LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
new file mode 100644
index 00000000000..b523fa5b711
--- /dev/null
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -0,0 +1,79 @@
+#![allow(unused)]
+#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)]
+
+extern crate regex;
+
+use regex::bytes::{Regex as BRegex, RegexBuilder as BRegexBuilder, RegexSet as BRegexSet};
+use regex::{Regex, RegexBuilder, RegexSet};
+
+const OPENING_PAREN: &str = "(";
+const NOT_A_REAL_REGEX: &str = "foobar";
+
+fn syntax_error() {
+    let pipe_in_wrong_position = Regex::new("|");
+    let pipe_in_wrong_position_builder = RegexBuilder::new("|");
+    let wrong_char_ranice = Regex::new("[z-a]");
+    let some_unicode = Regex::new("[é-è]");
+
+    let some_regex = Regex::new(OPENING_PAREN);
+
+    let binary_pipe_in_wrong_position = BRegex::new("|");
+    let some_binary_regex = BRegex::new(OPENING_PAREN);
+    let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
+
+    let closing_paren = ")";
+    let not_linted = Regex::new(closing_paren);
+
+    let set = RegexSet::new(&[r"[a-z]+@[a-z]+\.(com|org|net)", r"[a-z]+\.(com|org|net)"]);
+    let bset = BRegexSet::new(&[
+        r"[a-z]+@[a-z]+\.(com|org|net)",
+        r"[a-z]+\.(com|org|net)",
+        r".", // regression test
+    ]);
+
+    let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
+    let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
+
+    let raw_string_error = Regex::new(r"[...\/...]");
+    let raw_string_error = Regex::new(r#"[...\/...]"#);
+}
+
+fn trivial_regex() {
+    let trivial_eq = Regex::new("^foobar$");
+
+    let trivial_eq_builder = RegexBuilder::new("^foobar$");
+
+    let trivial_starts_with = Regex::new("^foobar");
+
+    let trivial_ends_with = Regex::new("foobar$");
+
+    let trivial_contains = Regex::new("foobar");
+
+    let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
+
+    let trivial_backslash = Regex::new("a\\.b");
+
+    // unlikely corner cases
+    let trivial_empty = Regex::new("");
+
+    let trivial_empty = Regex::new("^");
+
+    let trivial_empty = Regex::new("^$");
+
+    let binary_trivial_empty = BRegex::new("^$");
+
+    // non-trivial regexes
+    let non_trivial_dot = Regex::new("a.b");
+    let non_trivial_dot_builder = RegexBuilder::new("a.b");
+    let non_trivial_eq = Regex::new("^foo|bar$");
+    let non_trivial_starts_with = Regex::new("^foo|bar");
+    let non_trivial_ends_with = Regex::new("^foo|bar");
+    let non_trivial_ends_with = Regex::new("foo|bar");
+    let non_trivial_binary = BRegex::new("foo|bar");
+    let non_trivial_binary_builder = BRegexBuilder::new("foo|bar");
+}
+
+fn main() {
+    syntax_error();
+    trivial_regex();
+}
diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr
new file mode 100644
index 00000000000..1394a9b63bc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/regex.stderr
@@ -0,0 +1,171 @@
+error: trivial regex
+  --> $DIR/regex.rs:13:45
+   |
+LL |     let pipe_in_wrong_position = Regex::new("|");
+   |                                             ^^^
+   |
+   = note: `-D clippy::trivial-regex` implied by `-D warnings`
+   = help: the regex is unlikely to be useful as it is
+
+error: trivial regex
+  --> $DIR/regex.rs:14:60
+   |
+LL |     let pipe_in_wrong_position_builder = RegexBuilder::new("|");
+   |                                                            ^^^
+   |
+   = help: the regex is unlikely to be useful as it is
+
+error: regex syntax error: invalid character class range, the start must be <= the end
+  --> $DIR/regex.rs:15:42
+   |
+LL |     let wrong_char_ranice = Regex::new("[z-a]");
+   |                                          ^^^
+   |
+   = note: `-D clippy::invalid-regex` implied by `-D warnings`
+
+error: regex syntax error: invalid character class range, the start must be <= the end
+  --> $DIR/regex.rs:16:37
+   |
+LL |     let some_unicode = Regex::new("[é-è]");
+   |                                     ^^^
+
+error: regex syntax error on position 0: unclosed group
+  --> $DIR/regex.rs:18:33
+   |
+LL |     let some_regex = Regex::new(OPENING_PAREN);
+   |                                 ^^^^^^^^^^^^^
+
+error: trivial regex
+  --> $DIR/regex.rs:20:53
+   |
+LL |     let binary_pipe_in_wrong_position = BRegex::new("|");
+   |                                                     ^^^
+   |
+   = help: the regex is unlikely to be useful as it is
+
+error: regex syntax error on position 0: unclosed group
+  --> $DIR/regex.rs:21:41
+   |
+LL |     let some_binary_regex = BRegex::new(OPENING_PAREN);
+   |                                         ^^^^^^^^^^^^^
+
+error: regex syntax error on position 0: unclosed group
+  --> $DIR/regex.rs:22:56
+   |
+LL |     let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
+   |                                                        ^^^^^^^^^^^^^
+
+error: regex syntax error on position 0: unclosed group
+  --> $DIR/regex.rs:34:37
+   |
+LL |     let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
+   |                                     ^^^^^^^^^^^^^
+
+error: regex syntax error on position 0: unclosed group
+  --> $DIR/regex.rs:35:39
+   |
+LL |     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
+   |                                       ^^^^^^^^^^^^^
+
+error: regex syntax error: unrecognized escape sequence
+  --> $DIR/regex.rs:37:45
+   |
+LL |     let raw_string_error = Regex::new(r"[...//...]");
+   |                                             ^^
+
+error: regex syntax error: unrecognized escape sequence
+  --> $DIR/regex.rs:38:46
+   |
+LL |     let raw_string_error = Regex::new(r#"[...//...]"#);
+   |                                              ^^
+
+error: trivial regex
+  --> $DIR/regex.rs:42:33
+   |
+LL |     let trivial_eq = Regex::new("^foobar$");
+   |                                 ^^^^^^^^^^
+   |
+   = help: consider using `==` on `str`s
+
+error: trivial regex
+  --> $DIR/regex.rs:44:48
+   |
+LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
+   |                                                ^^^^^^^^^^
+   |
+   = help: consider using `==` on `str`s
+
+error: trivial regex
+  --> $DIR/regex.rs:46:42
+   |
+LL |     let trivial_starts_with = Regex::new("^foobar");
+   |                                          ^^^^^^^^^
+   |
+   = help: consider using `str::starts_with`
+
+error: trivial regex
+  --> $DIR/regex.rs:48:40
+   |
+LL |     let trivial_ends_with = Regex::new("foobar$");
+   |                                        ^^^^^^^^^
+   |
+   = help: consider using `str::ends_with`
+
+error: trivial regex
+  --> $DIR/regex.rs:50:39
+   |
+LL |     let trivial_contains = Regex::new("foobar");
+   |                                       ^^^^^^^^
+   |
+   = help: consider using `str::contains`
+
+error: trivial regex
+  --> $DIR/regex.rs:52:39
+   |
+LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
+   |                                       ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using `str::contains`
+
+error: trivial regex
+  --> $DIR/regex.rs:54:40
+   |
+LL |     let trivial_backslash = Regex::new("a/.b");
+   |                                        ^^^^^^^
+   |
+   = help: consider using `str::contains`
+
+error: trivial regex
+  --> $DIR/regex.rs:57:36
+   |
+LL |     let trivial_empty = Regex::new("");
+   |                                    ^^
+   |
+   = help: the regex is unlikely to be useful as it is
+
+error: trivial regex
+  --> $DIR/regex.rs:59:36
+   |
+LL |     let trivial_empty = Regex::new("^");
+   |                                    ^^^
+   |
+   = help: the regex is unlikely to be useful as it is
+
+error: trivial regex
+  --> $DIR/regex.rs:61:36
+   |
+LL |     let trivial_empty = Regex::new("^$");
+   |                                    ^^^^
+   |
+   = help: consider using `str::is_empty`
+
+error: trivial regex
+  --> $DIR/regex.rs:63:44
+   |
+LL |     let binary_trivial_empty = BRegex::new("^$");
+   |                                            ^^^^
+   |
+   = help: consider using `str::is_empty`
+
+error: aborting due to 23 previous errors
+
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
new file mode 100644
index 00000000000..13fbb6e2a6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -0,0 +1,19 @@
+//! Test for Clippy lint renames.
+// run-rustfix
+
+#![allow(dead_code)]
+// allow the new lint name here, to test if the new name works
+#![allow(clippy::module_name_repetitions)]
+#![allow(clippy::new_without_default)]
+#![allow(clippy::redundant_static_lifetimes)]
+// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::cognitive_complexity)]
+
+#[warn(clippy::module_name_repetitions)]
+fn main() {}
+
+#[warn(clippy::new_without_default)]
+struct Foo;
+
+#[warn(clippy::redundant_static_lifetimes)]
+fn foo() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
new file mode 100644
index 00000000000..cbd3b1e9166
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -0,0 +1,19 @@
+//! Test for Clippy lint renames.
+// run-rustfix
+
+#![allow(dead_code)]
+// allow the new lint name here, to test if the new name works
+#![allow(clippy::module_name_repetitions)]
+#![allow(clippy::new_without_default)]
+#![allow(clippy::redundant_static_lifetimes)]
+// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::cyclomatic_complexity)]
+
+#[warn(clippy::stutter)]
+fn main() {}
+
+#[warn(clippy::new_without_default_derive)]
+struct Foo;
+
+#[warn(clippy::const_static_lifetime)]
+fn foo() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
new file mode 100644
index 00000000000..a9e80394604
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -0,0 +1,34 @@
+error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
+  --> $DIR/rename.rs:10:9
+   |
+LL | #![warn(clippy::cyclomatic_complexity)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+  --> $DIR/rename.rs:12:8
+   |
+LL | #[warn(clippy::stutter)]
+   |        ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+  --> $DIR/rename.rs:15:8
+   |
+LL | #[warn(clippy::new_without_default_derive)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+  --> $DIR/rename.rs:18:8
+   |
+LL | #[warn(clippy::const_static_lifetime)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+
+error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
+  --> $DIR/rename.rs:10:9
+   |
+LL | #![warn(clippy::cyclomatic_complexity)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed
new file mode 100644
index 00000000000..cb91b841d2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed
@@ -0,0 +1,4 @@
+// run-rustfix
+
+#[clippy::cognitive_complexity = "1"]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.rs b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs
new file mode 100644
index 00000000000..b3ce2758067
--- /dev/null
+++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs
@@ -0,0 +1,4 @@
+// run-rustfix
+
+#[clippy::cyclomatic_complexity = "1"]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr
new file mode 100644
index 00000000000..a399ff52fb8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr
@@ -0,0 +1,8 @@
+error: Usage of deprecated attribute
+  --> $DIR/renamed_builtin_attr.rs:3:11
+   |
+LL | #[clippy::cyclomatic_complexity = "1"]
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/repl_uninit.rs b/src/tools/clippy/tests/ui/repl_uninit.rs
new file mode 100644
index 00000000000..346972b7bb4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/repl_uninit.rs
@@ -0,0 +1,35 @@
+#![allow(deprecated, invalid_value)]
+#![warn(clippy::all)]
+
+use std::mem;
+
+fn might_panic<X>(x: X) -> X {
+    // in practice this would be a possibly-panicky operation
+    x
+}
+
+fn main() {
+    let mut v = vec![0i32; 4];
+    // the following is UB if `might_panic` panics
+    unsafe {
+        let taken_v = mem::replace(&mut v, mem::uninitialized());
+        let new_v = might_panic(taken_v);
+        std::mem::forget(mem::replace(&mut v, new_v));
+    }
+
+    unsafe {
+        let taken_v = mem::replace(&mut v, mem::zeroed());
+        let new_v = might_panic(taken_v);
+        std::mem::forget(mem::replace(&mut v, new_v));
+    }
+
+    // this is silly but OK, because usize is a primitive type
+    let mut u: usize = 42;
+    let uref = &mut u;
+    let taken_u = unsafe { mem::replace(uref, mem::zeroed()) };
+    *uref = taken_u + 1;
+
+    // this is still not OK, because uninit
+    let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) };
+    *uref = taken_u + 1;
+}
diff --git a/src/tools/clippy/tests/ui/repl_uninit.stderr b/src/tools/clippy/tests/ui/repl_uninit.stderr
new file mode 100644
index 00000000000..c1f55d7601e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/repl_uninit.stderr
@@ -0,0 +1,27 @@
+error: replacing with `mem::uninitialized()`
+  --> $DIR/repl_uninit.rs:15:23
+   |
+LL |         let taken_v = mem::replace(&mut v, mem::uninitialized());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings`
+   = help: consider using the `take_mut` crate instead
+
+error: replacing with `mem::zeroed()`
+  --> $DIR/repl_uninit.rs:21:23
+   |
+LL |         let taken_v = mem::replace(&mut v, mem::zeroed());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a default value or the `take_mut` crate instead
+
+error: replacing with `mem::uninitialized()`
+  --> $DIR/repl_uninit.rs:33:28
+   |
+LL |     let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `take_mut` crate instead
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
new file mode 100644
index 00000000000..38fc9969804
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::rest_pat_in_fully_bound_structs)]
+
+struct A {
+    a: i32,
+    b: i64,
+    c: &'static str,
+}
+
+macro_rules! foo {
+    ($param:expr) => {
+        match $param {
+            A { a: 0, b: 0, c: "", .. } => {},
+            _ => {},
+        }
+    };
+}
+
+fn main() {
+    let a_struct = A { a: 5, b: 42, c: "A" };
+
+    match a_struct {
+        A { a: 5, b: 42, c: "", .. } => {}, // Lint
+        A { a: 0, b: 0, c: "", .. } => {},  // Lint
+        _ => {},
+    }
+
+    match a_struct {
+        A { a: 5, b: 42, .. } => {},
+        A { a: 0, b: 0, c: "", .. } => {}, // Lint
+        _ => {},
+    }
+
+    // No lint
+    match a_struct {
+        A { a: 5, .. } => {},
+        A { a: 0, b: 0, .. } => {},
+        _ => {},
+    }
+
+    // No lint
+    foo!(a_struct);
+}
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
new file mode 100644
index 00000000000..57ebd47f8c7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -0,0 +1,27 @@
+error: unnecessary use of `..` pattern in struct binding. All fields were already bound
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:22:9
+   |
+LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings`
+   = help: consider removing `..` from this binding
+
+error: unnecessary use of `..` pattern in struct binding. All fields were already bound
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9
+   |
+LL |         A { a: 0, b: 0, c: "", .. } => {},  // Lint
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing `..` from this binding
+
+error: unnecessary use of `..` pattern in struct binding. All fields were already bound
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:29:9
+   |
+LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing `..` from this binding
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
new file mode 100644
index 00000000000..331531b5165
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
@@ -0,0 +1,19 @@
+// run-rustfix
+
+#![warn(clippy::result_map_or_into_option)]
+
+fn main() {
+    let opt: Result<u32, &str> = Ok(1);
+    let _ = opt.ok();
+
+    let rewrap = |s: u32| -> Option<u32> { Some(s) };
+
+    // A non-Some `f` arg should not emit the lint
+    let opt: Result<u32, &str> = Ok(1);
+    let _ = opt.map_or(None, rewrap);
+
+    // A non-Some `f` closure where the argument is not used as the
+    // return should not emit the lint
+    let opt: Result<u32, &str> = Ok(1);
+    opt.map_or(None, |_x| Some(1));
+}
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
new file mode 100644
index 00000000000..3058480e2ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
@@ -0,0 +1,19 @@
+// run-rustfix
+
+#![warn(clippy::result_map_or_into_option)]
+
+fn main() {
+    let opt: Result<u32, &str> = Ok(1);
+    let _ = opt.map_or(None, Some);
+
+    let rewrap = |s: u32| -> Option<u32> { Some(s) };
+
+    // A non-Some `f` arg should not emit the lint
+    let opt: Result<u32, &str> = Ok(1);
+    let _ = opt.map_or(None, rewrap);
+
+    // A non-Some `f` closure where the argument is not used as the
+    // return should not emit the lint
+    let opt: Result<u32, &str> = Ok(1);
+    opt.map_or(None, |_x| Some(1));
+}
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr
new file mode 100644
index 00000000000..febf32147d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr
@@ -0,0 +1,10 @@
+error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead
+  --> $DIR/result_map_or_into_option.rs:7:13
+   |
+LL |     let _ = opt.map_or(None, Some);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()`
+   |
+   = note: `-D clippy::result-map-or-into-option` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
new file mode 100644
index 00000000000..1d0a3ecd0ff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
@@ -0,0 +1,80 @@
+// run-rustfix
+
+#![warn(clippy::result_map_unit_fn)]
+#![allow(unused)]
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+struct HasResult {
+    field: Result<usize, usize>,
+}
+
+impl HasResult {
+    fn do_result_nothing(self: &Self, value: usize) {}
+
+    fn do_result_plus_one(self: &Self, value: usize) -> usize {
+        value + 1
+    }
+}
+
+#[rustfmt::skip]
+fn result_map_unit_fn() {
+    let x = HasResult { field: Ok(10) };
+
+    x.field.map(plus_one);
+    let _: Result<(), usize> = x.field.map(do_nothing);
+
+    if let Ok(x_field) = x.field { do_nothing(x_field) }
+
+    if let Ok(x_field) = x.field { do_nothing(x_field) }
+
+    if let Ok(x_field) = x.field { diverge(x_field) }
+
+    let captured = 10;
+    if let Ok(value) = x.field { do_nothing(value + captured) };
+    let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
+
+    if let Ok(value) = x.field { x.do_result_nothing(value + captured) }
+
+    if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }
+
+
+    if let Ok(value) = x.field { do_nothing(value + captured) }
+
+    if let Ok(value) = x.field { do_nothing(value + captured) }
+
+    if let Ok(value) = x.field { do_nothing(value + captured); }
+
+    if let Ok(value) = x.field { do_nothing(value + captured); }
+
+
+    if let Ok(value) = x.field { diverge(value + captured) }
+
+    if let Ok(value) = x.field { diverge(value + captured) }
+
+    if let Ok(value) = x.field { diverge(value + captured); }
+
+    if let Ok(value) = x.field { diverge(value + captured); }
+
+
+    x.field.map(|value| plus_one(value + captured));
+    x.field.map(|value| { plus_one(value + captured) });
+    if let Ok(value) = x.field { let y = plus_one(value + captured); }
+
+    if let Ok(value) = x.field { plus_one(value + captured); }
+
+    if let Ok(value) = x.field { plus_one(value + captured); }
+
+
+    if let Ok(ref value) = x.field { do_nothing(value + captured) }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
new file mode 100644
index 00000000000..2fe18f923f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
@@ -0,0 +1,80 @@
+// run-rustfix
+
+#![warn(clippy::result_map_unit_fn)]
+#![allow(unused)]
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+struct HasResult {
+    field: Result<usize, usize>,
+}
+
+impl HasResult {
+    fn do_result_nothing(self: &Self, value: usize) {}
+
+    fn do_result_plus_one(self: &Self, value: usize) -> usize {
+        value + 1
+    }
+}
+
+#[rustfmt::skip]
+fn result_map_unit_fn() {
+    let x = HasResult { field: Ok(10) };
+
+    x.field.map(plus_one);
+    let _: Result<(), usize> = x.field.map(do_nothing);
+
+    x.field.map(do_nothing);
+
+    x.field.map(do_nothing);
+
+    x.field.map(diverge);
+
+    let captured = 10;
+    if let Ok(value) = x.field { do_nothing(value + captured) };
+    let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
+
+    x.field.map(|value| x.do_result_nothing(value + captured));
+
+    x.field.map(|value| { x.do_result_plus_one(value + captured); });
+
+
+    x.field.map(|value| do_nothing(value + captured));
+
+    x.field.map(|value| { do_nothing(value + captured) });
+
+    x.field.map(|value| { do_nothing(value + captured); });
+
+    x.field.map(|value| { { do_nothing(value + captured); } });
+
+
+    x.field.map(|value| diverge(value + captured));
+
+    x.field.map(|value| { diverge(value + captured) });
+
+    x.field.map(|value| { diverge(value + captured); });
+
+    x.field.map(|value| { { diverge(value + captured); } });
+
+
+    x.field.map(|value| plus_one(value + captured));
+    x.field.map(|value| { plus_one(value + captured) });
+    x.field.map(|value| { let y = plus_one(value + captured); });
+
+    x.field.map(|value| { plus_one(value + captured); });
+
+    x.field.map(|value| { { plus_one(value + captured); } });
+
+
+    x.field.map(|ref value| { do_nothing(value + captured) });
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
new file mode 100644
index 00000000000..467e00263cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
@@ -0,0 +1,140 @@
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:35:5
+   |
+LL |     x.field.map(do_nothing);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
+   |
+   = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
+
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:37:5
+   |
+LL |     x.field.map(do_nothing);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
+
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:39:5
+   |
+LL |     x.field.map(diverge);
+   |     ^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:45:5
+   |
+LL |     x.field.map(|value| x.do_result_nothing(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:47:5
+   |
+LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:50:5
+   |
+LL |     x.field.map(|value| do_nothing(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:52:5
+   |
+LL |     x.field.map(|value| { do_nothing(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:54:5
+   |
+LL |     x.field.map(|value| { do_nothing(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:56:5
+   |
+LL |     x.field.map(|value| { { do_nothing(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:59:5
+   |
+LL |     x.field.map(|value| diverge(value + captured));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:61:5
+   |
+LL |     x.field.map(|value| { diverge(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:63:5
+   |
+LL |     x.field.map(|value| { diverge(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:65:5
+   |
+LL |     x.field.map(|value| { { diverge(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:70:5
+   |
+LL |     x.field.map(|value| { let y = plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:72:5
+   |
+LL |     x.field.map(|value| { plus_one(value + captured); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:74:5
+   |
+LL |     x.field.map(|value| { { plus_one(value + captured); } });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_fixable.rs:77:5
+   |
+LL |     x.field.map(|ref value| { do_nothing(value + captured) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }`
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs
new file mode 100644
index 00000000000..b197c609d7b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs
@@ -0,0 +1,46 @@
+#![warn(clippy::result_map_unit_fn)]
+#![feature(never_type)]
+#![allow(unused)]
+
+struct HasResult {
+    field: Result<usize, usize>,
+}
+
+fn do_nothing<T>(_: T) {}
+
+fn diverge<T>(_: T) -> ! {
+    panic!()
+}
+
+fn plus_one(value: usize) -> usize {
+    value + 1
+}
+
+#[rustfmt::skip]
+fn result_map_unit_fn() {
+    let x = HasResult { field: Ok(10) };
+
+    x.field.map(|value| { do_nothing(value); do_nothing(value) });
+
+    x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+
+    // Suggestion for the let block should be `{ ... }` as it's too difficult to build a
+    // proper suggestion for these cases
+    x.field.map(|value| {
+        do_nothing(value);
+        do_nothing(value)
+    });
+    x.field.map(|value| { do_nothing(value); do_nothing(value); });
+
+    // The following should suggest `if let Ok(_X) ...` as it's difficult to generate a proper let variable name for them
+    let res: Result<!, usize> = Ok(42).map(diverge);
+    "12".parse::<i32>().map(diverge);
+
+    let res: Result<(), usize> = Ok(plus_one(1)).map(do_nothing);
+
+    // Should suggest `if let Ok(_y) ...` to not override the existing foo variable
+    let y: Result<usize, usize> = Ok(42);
+    y.map(do_nothing);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
new file mode 100644
index 00000000000..b23cc608621
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
@@ -0,0 +1,58 @@
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:23:5
+   |
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { ... }`
+   |
+   = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:25:5
+   |
+LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { ... }`
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:29:5
+   |
+LL |        x.field.map(|value| {
+   |   _____^
+   |  |_____|
+   | ||
+LL | ||         do_nothing(value);
+LL | ||         do_nothing(value)
+LL | ||     });
+   | ||______^- help: try this: `if let Ok(value) = x.field { ... }`
+   | |_______|
+   | 
+
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:33:5
+   |
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(value) = x.field { ... }`
+
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:37:5
+   |
+LL |     "12".parse::<i32>().map(diverge);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }`
+
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+  --> $DIR/result_map_unit_fn_unfixable.rs:43:5
+   |
+LL |     y.map(do_nothing);
+   |     ^^^^^^^^^^^^^^^^^-
+   |     |
+   |     help: try this: `if let Ok(_y) = y { do_nothing(_y) }`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/result_map_unwrap_or_else.rs b/src/tools/clippy/tests/ui/result_map_unwrap_or_else.rs
new file mode 100644
index 00000000000..40751bfebe6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unwrap_or_else.rs
@@ -0,0 +1,23 @@
+// aux-build:option_helpers.rs
+
+//! Checks implementation of `RESULT_MAP_UNWRAP_OR_ELSE`
+
+#![warn(clippy::result_map_unwrap_or_else)]
+
+#[macro_use]
+extern crate option_helpers;
+
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // Check RESULT_MAP_UNWRAP_OR_ELSE
+    // single line case
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
+                                                      // multi line cases
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+    // macro case
+    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_map_unwrap_or_else.stderr b/src/tools/clippy/tests/ui/result_map_unwrap_or_else.stderr
new file mode 100644
index 00000000000..ec7bc8f1241
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_map_unwrap_or_else.stderr
@@ -0,0 +1,27 @@
+error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:15:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::result-map-unwrap-or-else` implied by `-D warnings`
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)`
+
+error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:17:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)`
+
+error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:18:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
new file mode 100644
index 00000000000..686867cf5c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
@@ -0,0 +1,80 @@
+#![warn(clippy::same_functions_in_if_condition)]
+#![allow(clippy::ifs_same_cond)] // This warning is different from `ifs_same_cond`.
+#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks
+
+fn function() -> bool {
+    true
+}
+
+fn fn_arg(_arg: u8) -> bool {
+    true
+}
+
+struct Struct;
+
+impl Struct {
+    fn method(&self) -> bool {
+        true
+    }
+    fn method_arg(&self, _arg: u8) -> bool {
+        true
+    }
+}
+
+fn ifs_same_cond_fn() {
+    let a = 0;
+    let obj = Struct;
+
+    if function() {
+    } else if function() {
+        //~ ERROR ifs same condition
+    }
+
+    if fn_arg(a) {
+    } else if fn_arg(a) {
+        //~ ERROR ifs same condition
+    }
+
+    if obj.method() {
+    } else if obj.method() {
+        //~ ERROR ifs same condition
+    }
+
+    if obj.method_arg(a) {
+    } else if obj.method_arg(a) {
+        //~ ERROR ifs same condition
+    }
+
+    let mut v = vec![1];
+    if v.pop() == None {
+        //~ ERROR ifs same condition
+    } else if v.pop() == None {
+    }
+
+    if v.len() == 42 {
+        //~ ERROR ifs same condition
+    } else if v.len() == 42 {
+    }
+
+    if v.len() == 1 {
+        // ok, different conditions
+    } else if v.len() == 2 {
+    }
+
+    if fn_arg(0) {
+        // ok, different arguments.
+    } else if fn_arg(1) {
+    }
+
+    if obj.method_arg(0) {
+        // ok, different arguments.
+    } else if obj.method_arg(1) {
+    }
+
+    if a == 1 {
+        // ok, warning is on `ifs_same_cond` behalf.
+    } else if a == 1 {
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
new file mode 100644
index 00000000000..363a03846d2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
@@ -0,0 +1,75 @@
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:29:15
+   |
+LL |     } else if function() {
+   |               ^^^^^^^^^^
+   |
+   = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings`
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:28:8
+   |
+LL |     if function() {
+   |        ^^^^^^^^^^
+
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:34:15
+   |
+LL |     } else if fn_arg(a) {
+   |               ^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:33:8
+   |
+LL |     if fn_arg(a) {
+   |        ^^^^^^^^^
+
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:39:15
+   |
+LL |     } else if obj.method() {
+   |               ^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:38:8
+   |
+LL |     if obj.method() {
+   |        ^^^^^^^^^^^^
+
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:44:15
+   |
+LL |     } else if obj.method_arg(a) {
+   |               ^^^^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:43:8
+   |
+LL |     if obj.method_arg(a) {
+   |        ^^^^^^^^^^^^^^^^^
+
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:51:15
+   |
+LL |     } else if v.pop() == None {
+   |               ^^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:49:8
+   |
+LL |     if v.pop() == None {
+   |        ^^^^^^^^^^^^^^^
+
+error: this `if` has the same function call as a previous `if`
+  --> $DIR/same_functions_in_if_condition.rs:56:15
+   |
+LL |     } else if v.len() == 42 {
+   |               ^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/same_functions_in_if_condition.rs:54:8
+   |
+LL |     if v.len() == 42 {
+   |        ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/serde.rs b/src/tools/clippy/tests/ui/serde.rs
new file mode 100644
index 00000000000..5843344eba8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/serde.rs
@@ -0,0 +1,47 @@
+#![warn(clippy::serde_api_misuse)]
+#![allow(dead_code)]
+
+extern crate serde;
+
+struct A;
+
+impl<'de> serde::de::Visitor<'de> for A {
+    type Value = ();
+
+    fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        unimplemented!()
+    }
+
+    fn visit_str<E>(self, _v: &str) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        unimplemented!()
+    }
+
+    fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        unimplemented!()
+    }
+}
+
+struct B;
+
+impl<'de> serde::de::Visitor<'de> for B {
+    type Value = ();
+
+    fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        unimplemented!()
+    }
+
+    fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/serde.stderr b/src/tools/clippy/tests/ui/serde.stderr
new file mode 100644
index 00000000000..760c9c9908a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/serde.stderr
@@ -0,0 +1,15 @@
+error: you should not implement `visit_string` without also implementing `visit_str`
+  --> $DIR/serde.rs:39:5
+   |
+LL | /     fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
+LL | |     where
+LL | |         E: serde::de::Error,
+LL | |     {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::serde-api-misuse` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
new file mode 100644
index 00000000000..bd91ae4e934
--- /dev/null
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -0,0 +1,53 @@
+#![warn(
+    clippy::all,
+    clippy::pedantic,
+    clippy::shadow_same,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated
+)]
+#![allow(
+    unused_parens,
+    unused_variables,
+    clippy::missing_docs_in_private_items,
+    clippy::single_match
+)]
+
+fn id<T>(x: T) -> T {
+    x
+}
+
+#[must_use]
+fn first(x: (isize, isize)) -> isize {
+    x.0
+}
+
+fn main() {
+    let mut x = 1;
+    let x = &mut x;
+    let x = { x };
+    let x = (&*x);
+    let x = { *x + 1 };
+    let x = id(x);
+    let x = (1, x);
+    let x = first(x);
+    let y = 1;
+    let x = y;
+
+    let x;
+    x = 42;
+
+    let o = Some(1_u8);
+
+    if let Some(p) = o {
+        assert_eq!(1, p);
+    }
+    match o {
+        Some(p) => p, // no error, because the p above is in its own scope
+        None => 0,
+    };
+
+    match (x, o) {
+        (1, Some(a)) | (a, Some(1)) => (), // no error though `a` appears twice
+        _ => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
new file mode 100644
index 00000000000..7fa58cf7649
--- /dev/null
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -0,0 +1,138 @@
+error: `x` is shadowed by itself in `&mut x`
+  --> $DIR/shadow.rs:26:5
+   |
+LL |     let x = &mut x;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::shadow-same` implied by `-D warnings`
+note: previous binding is here
+  --> $DIR/shadow.rs:25:13
+   |
+LL |     let mut x = 1;
+   |             ^
+
+error: `x` is shadowed by itself in `{ x }`
+  --> $DIR/shadow.rs:27:5
+   |
+LL |     let x = { x };
+   |     ^^^^^^^^^^^^^^
+   |
+note: previous binding is here
+  --> $DIR/shadow.rs:26:9
+   |
+LL |     let x = &mut x;
+   |         ^
+
+error: `x` is shadowed by itself in `(&*x)`
+  --> $DIR/shadow.rs:28:5
+   |
+LL |     let x = (&*x);
+   |     ^^^^^^^^^^^^^^
+   |
+note: previous binding is here
+  --> $DIR/shadow.rs:27:9
+   |
+LL |     let x = { x };
+   |         ^
+
+error: `x` is shadowed by `{ *x + 1 }` which reuses the original value
+  --> $DIR/shadow.rs:29:9
+   |
+LL |     let x = { *x + 1 };
+   |         ^
+   |
+   = note: `-D clippy::shadow-reuse` implied by `-D warnings`
+note: initialization happens here
+  --> $DIR/shadow.rs:29:13
+   |
+LL |     let x = { *x + 1 };
+   |             ^^^^^^^^^^
+note: previous binding is here
+  --> $DIR/shadow.rs:28:9
+   |
+LL |     let x = (&*x);
+   |         ^
+
+error: `x` is shadowed by `id(x)` which reuses the original value
+  --> $DIR/shadow.rs:30:9
+   |
+LL |     let x = id(x);
+   |         ^
+   |
+note: initialization happens here
+  --> $DIR/shadow.rs:30:13
+   |
+LL |     let x = id(x);
+   |             ^^^^^
+note: previous binding is here
+  --> $DIR/shadow.rs:29:9
+   |
+LL |     let x = { *x + 1 };
+   |         ^
+
+error: `x` is shadowed by `(1, x)` which reuses the original value
+  --> $DIR/shadow.rs:31:9
+   |
+LL |     let x = (1, x);
+   |         ^
+   |
+note: initialization happens here
+  --> $DIR/shadow.rs:31:13
+   |
+LL |     let x = (1, x);
+   |             ^^^^^^
+note: previous binding is here
+  --> $DIR/shadow.rs:30:9
+   |
+LL |     let x = id(x);
+   |         ^
+
+error: `x` is shadowed by `first(x)` which reuses the original value
+  --> $DIR/shadow.rs:32:9
+   |
+LL |     let x = first(x);
+   |         ^
+   |
+note: initialization happens here
+  --> $DIR/shadow.rs:32:13
+   |
+LL |     let x = first(x);
+   |             ^^^^^^^^
+note: previous binding is here
+  --> $DIR/shadow.rs:31:9
+   |
+LL |     let x = (1, x);
+   |         ^
+
+error: `x` is shadowed by `y`
+  --> $DIR/shadow.rs:34:9
+   |
+LL |     let x = y;
+   |         ^
+   |
+   = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
+note: initialization happens here
+  --> $DIR/shadow.rs:34:13
+   |
+LL |     let x = y;
+   |             ^
+note: previous binding is here
+  --> $DIR/shadow.rs:32:9
+   |
+LL |     let x = first(x);
+   |         ^
+
+error: `x` shadows a previous declaration
+  --> $DIR/shadow.rs:36:5
+   |
+LL |     let x;
+   |     ^^^^^^
+   |
+note: previous binding is here
+  --> $DIR/shadow.rs:34:9
+   |
+LL |     let x = y;
+   |         ^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.fixed b/src/tools/clippy/tests/ui/short_circuit_statement.fixed
new file mode 100644
index 00000000000..af0a397bd1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/short_circuit_statement.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::short_circuit_statement)]
+#![allow(clippy::nonminimal_bool)]
+
+fn main() {
+    if f() { g(); }
+    if !f() { g(); }
+    if !(1 == 2) { g(); }
+}
+
+fn f() -> bool {
+    true
+}
+
+fn g() -> bool {
+    false
+}
diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.rs b/src/tools/clippy/tests/ui/short_circuit_statement.rs
new file mode 100644
index 00000000000..73a55bf1f5e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/short_circuit_statement.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::short_circuit_statement)]
+#![allow(clippy::nonminimal_bool)]
+
+fn main() {
+    f() && g();
+    f() || g();
+    1 == 2 || g();
+}
+
+fn f() -> bool {
+    true
+}
+
+fn g() -> bool {
+    false
+}
diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.stderr b/src/tools/clippy/tests/ui/short_circuit_statement.stderr
new file mode 100644
index 00000000000..0a3f60c3d13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/short_circuit_statement.stderr
@@ -0,0 +1,22 @@
+error: boolean short circuit operator in statement may be clearer using an explicit test
+  --> $DIR/short_circuit_statement.rs:7:5
+   |
+LL |     f() && g();
+   |     ^^^^^^^^^^^ help: replace it with: `if f() { g(); }`
+   |
+   = note: `-D clippy::short-circuit-statement` implied by `-D warnings`
+
+error: boolean short circuit operator in statement may be clearer using an explicit test
+  --> $DIR/short_circuit_statement.rs:8:5
+   |
+LL |     f() || g();
+   |     ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }`
+
+error: boolean short circuit operator in statement may be clearer using an explicit test
+  --> $DIR/short_circuit_statement.rs:9:5
+   |
+LL |     1 == 2 || g();
+   |     ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs
new file mode 100644
index 00000000000..6796b15289e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/similar_names.rs
@@ -0,0 +1,103 @@
+#![warn(clippy::similar_names)]
+#![allow(unused, clippy::println_empty_string)]
+
+struct Foo {
+    apple: i32,
+    bpple: i32,
+}
+
+fn main() {
+    let specter: i32;
+    let spectre: i32;
+
+    let apple: i32;
+
+    let bpple: i32;
+
+    let cpple: i32;
+
+    let a_bar: i32;
+    let b_bar: i32;
+    let c_bar: i32;
+
+    let items = [5];
+    for item in &items {
+        loop {}
+    }
+
+    let foo_x: i32;
+    let foo_y: i32;
+
+    let rhs: i32;
+    let lhs: i32;
+
+    let bla_rhs: i32;
+    let bla_lhs: i32;
+
+    let blubrhs: i32;
+    let blublhs: i32;
+
+    let blubx: i32;
+    let bluby: i32;
+
+    let cake: i32;
+    let cakes: i32;
+    let coke: i32;
+
+    match 5 {
+        cheese @ 1 => {},
+        rabbit => panic!(),
+    }
+    let cheese: i32;
+    match (42, 43) {
+        (cheese1, 1) => {},
+        (cheese2, 2) => panic!(),
+        _ => println!(""),
+    }
+    let ipv4: i32;
+    let ipv6: i32;
+    let abcd1: i32;
+    let abdc2: i32;
+    let xyz1abc: i32;
+    let xyz2abc: i32;
+    let xyzeabc: i32;
+
+    let parser: i32;
+    let parsed: i32;
+    let parsee: i32;
+
+    let setter: i32;
+    let getter: i32;
+    let tx1: i32;
+    let rx1: i32;
+    let tx_cake: i32;
+    let rx_cake: i32;
+}
+
+fn foo() {
+    let Foo { apple, bpple } = unimplemented!();
+    let Foo {
+        apple: spring,
+        bpple: sprang,
+    } = unimplemented!();
+}
+
+// false positive similar_names (#3057, #2651)
+// clippy claimed total_reg_src_size and total_size and
+// numb_reg_src_checkouts and total_bin_size were similar
+#[derive(Debug, Clone)]
+pub(crate) struct DirSizes {
+    pub(crate) total_size: u64,
+    pub(crate) numb_bins: u64,
+    pub(crate) total_bin_size: u64,
+    pub(crate) total_reg_size: u64,
+    pub(crate) total_git_db_size: u64,
+    pub(crate) total_git_repos_bare_size: u64,
+    pub(crate) numb_git_repos_bare_repos: u64,
+    pub(crate) numb_git_checkouts: u64,
+    pub(crate) total_git_chk_size: u64,
+    pub(crate) total_reg_cache_size: u64,
+    pub(crate) total_reg_src_size: u64,
+    pub(crate) numb_reg_cache_entries: u64,
+    pub(crate) numb_reg_src_checkouts: u64,
+}
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
new file mode 100644
index 00000000000..0256f126a94
--- /dev/null
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -0,0 +1,107 @@
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:15:9
+   |
+LL |     let bpple: i32;
+   |         ^^^^^
+   |
+   = note: `-D clippy::similar-names` implied by `-D warnings`
+note: existing binding defined here
+  --> $DIR/similar_names.rs:13:9
+   |
+LL |     let apple: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `b_pple`
+  --> $DIR/similar_names.rs:15:9
+   |
+LL |     let bpple: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:17:9
+   |
+LL |     let cpple: i32;
+   |         ^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:13:9
+   |
+LL |     let apple: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `c_pple`
+  --> $DIR/similar_names.rs:17:9
+   |
+LL |     let cpple: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:41:9
+   |
+LL |     let bluby: i32;
+   |         ^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:40:9
+   |
+LL |     let blubx: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `blub_y`
+  --> $DIR/similar_names.rs:41:9
+   |
+LL |     let bluby: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:45:9
+   |
+LL |     let coke: i32;
+   |         ^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:43:9
+   |
+LL |     let cake: i32;
+   |         ^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:63:9
+   |
+LL |     let xyzeabc: i32;
+   |         ^^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:61:9
+   |
+LL |     let xyz1abc: i32;
+   |         ^^^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:67:9
+   |
+LL |     let parsee: i32;
+   |         ^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:65:9
+   |
+LL |     let parser: i32;
+   |         ^^^^^^
+help: separate the discriminating character by an underscore like: `parse_e`
+  --> $DIR/similar_names.rs:67:9
+   |
+LL |     let parsee: i32;
+   |         ^^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:81:16
+   |
+LL |         bpple: sprang,
+   |                ^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:80:16
+   |
+LL |         apple: spring,
+   |                ^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
new file mode 100644
index 00000000000..3871c4f2268
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+
+use std::collections::HashSet;
+
+fn main() {
+    let x = "foo";
+    x.split('x');
+    x.split("xx");
+    x.split('x');
+
+    let y = "x";
+    x.split(y);
+    // Not yet testing for multi-byte characters
+    // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern`
+    // should have done this but produced an ICE
+    //
+    // We may not want to suggest changing these anyway
+    // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984
+    x.split("ß");
+    x.split("ℝ");
+    x.split("💣");
+    // Can't use this lint for unicode code points which don't fit in a char
+    x.split("❤️");
+    x.contains('x');
+    x.starts_with('x');
+    x.ends_with('x');
+    x.find('x');
+    x.rfind('x');
+    x.rsplit('x');
+    x.split_terminator('x');
+    x.rsplit_terminator('x');
+    x.splitn(0, 'x');
+    x.rsplitn(0, 'x');
+    x.matches('x');
+    x.rmatches('x');
+    x.match_indices('x');
+    x.rmatch_indices('x');
+    x.trim_start_matches('x');
+    x.trim_end_matches('x');
+    // Make sure we escape characters correctly.
+    x.split('\n');
+    x.split('\'');
+    x.split('\'');
+
+    let h = HashSet::<String>::new();
+    h.contains("X"); // should not warn
+
+    x.replace(";", ",").split(','); // issue #2978
+    x.starts_with('\x03'); // issue #2996
+
+    // Issue #3204
+    const S: &str = "#";
+    x.find(S);
+
+    // Raw string
+    x.split('a');
+    x.split('a');
+    x.split('a');
+    x.split('\'');
+    x.split('#');
+}
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
new file mode 100644
index 00000000000..32afe339cd8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+
+use std::collections::HashSet;
+
+fn main() {
+    let x = "foo";
+    x.split("x");
+    x.split("xx");
+    x.split('x');
+
+    let y = "x";
+    x.split(y);
+    // Not yet testing for multi-byte characters
+    // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern`
+    // should have done this but produced an ICE
+    //
+    // We may not want to suggest changing these anyway
+    // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984
+    x.split("ß");
+    x.split("ℝ");
+    x.split("💣");
+    // Can't use this lint for unicode code points which don't fit in a char
+    x.split("❤️");
+    x.contains("x");
+    x.starts_with("x");
+    x.ends_with("x");
+    x.find("x");
+    x.rfind("x");
+    x.rsplit("x");
+    x.split_terminator("x");
+    x.rsplit_terminator("x");
+    x.splitn(0, "x");
+    x.rsplitn(0, "x");
+    x.matches("x");
+    x.rmatches("x");
+    x.match_indices("x");
+    x.rmatch_indices("x");
+    x.trim_start_matches("x");
+    x.trim_end_matches("x");
+    // Make sure we escape characters correctly.
+    x.split("\n");
+    x.split("'");
+    x.split("\'");
+
+    let h = HashSet::<String>::new();
+    h.contains("X"); // should not warn
+
+    x.replace(";", ",").split(","); // issue #2978
+    x.starts_with("\x03"); // issue #2996
+
+    // Issue #3204
+    const S: &str = "#";
+    x.find(S);
+
+    // Raw string
+    x.split(r"a");
+    x.split(r#"a"#);
+    x.split(r###"a"###);
+    x.split(r###"'"###);
+    x.split(r###"#"###);
+}
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
new file mode 100644
index 00000000000..fe7211c53f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -0,0 +1,166 @@
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:9:13
+   |
+LL |     x.split("x");
+   |             ^^^ help: try using a `char` instead: `'x'`
+   |
+   = note: `-D clippy::single-char-pattern` implied by `-D warnings`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:26:16
+   |
+LL |     x.contains("x");
+   |                ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:27:19
+   |
+LL |     x.starts_with("x");
+   |                   ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:28:17
+   |
+LL |     x.ends_with("x");
+   |                 ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:29:12
+   |
+LL |     x.find("x");
+   |            ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:30:13
+   |
+LL |     x.rfind("x");
+   |             ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:31:14
+   |
+LL |     x.rsplit("x");
+   |              ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:32:24
+   |
+LL |     x.split_terminator("x");
+   |                        ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:33:25
+   |
+LL |     x.rsplit_terminator("x");
+   |                         ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:34:17
+   |
+LL |     x.splitn(0, "x");
+   |                 ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:35:18
+   |
+LL |     x.rsplitn(0, "x");
+   |                  ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:36:15
+   |
+LL |     x.matches("x");
+   |               ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:37:16
+   |
+LL |     x.rmatches("x");
+   |                ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:38:21
+   |
+LL |     x.match_indices("x");
+   |                     ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:39:22
+   |
+LL |     x.rmatch_indices("x");
+   |                      ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:40:26
+   |
+LL |     x.trim_start_matches("x");
+   |                          ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:41:24
+   |
+LL |     x.trim_end_matches("x");
+   |                        ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:43:13
+   |
+LL |     x.split("/n");
+   |             ^^^^ help: try using a `char` instead: `'/n'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:44:13
+   |
+LL |     x.split("'");
+   |             ^^^ help: try using a `char` instead: `'/''`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:45:13
+   |
+LL |     x.split("/'");
+   |             ^^^^ help: try using a `char` instead: `'/''`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:50:31
+   |
+LL |     x.replace(";", ",").split(","); // issue #2978
+   |                               ^^^ help: try using a `char` instead: `','`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:51:19
+   |
+LL |     x.starts_with("/x03"); // issue #2996
+   |                   ^^^^^^ help: try using a `char` instead: `'/x03'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:58:13
+   |
+LL |     x.split(r"a");
+   |             ^^^^ help: try using a `char` instead: `'a'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:59:13
+   |
+LL |     x.split(r#"a"#);
+   |             ^^^^^^ help: try using a `char` instead: `'a'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:60:13
+   |
+LL |     x.split(r###"a"###);
+   |             ^^^^^^^^^^ help: try using a `char` instead: `'a'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:61:13
+   |
+LL |     x.split(r###"'"###);
+   |             ^^^^^^^^^^ help: try using a `char` instead: `'/''`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:62:13
+   |
+LL |     x.split(r###"#"###);
+   |             ^^^^^^^^^^ help: try using a `char` instead: `'#'`
+
+error: aborting due to 27 previous errors
+
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed
new file mode 100644
index 00000000000..a7a8499b58f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::single_component_path_imports)]
+#![allow(unused_imports)]
+
+
+use serde as edres;
+pub use serde;
+
+macro_rules! m {
+    () => {
+        use regex;
+    };
+}
+
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+
+    // False positive #5154, shouldn't trigger lint.
+    m!();
+}
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.rs b/src/tools/clippy/tests/ui/single_component_path_imports.rs
new file mode 100644
index 00000000000..9a427e90ad3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::single_component_path_imports)]
+#![allow(unused_imports)]
+
+use regex;
+use serde as edres;
+pub use serde;
+
+macro_rules! m {
+    () => {
+        use regex;
+    };
+}
+
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+
+    // False positive #5154, shouldn't trigger lint.
+    m!();
+}
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.stderr b/src/tools/clippy/tests/ui/single_component_path_imports.stderr
new file mode 100644
index 00000000000..519ada0169a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.stderr
@@ -0,0 +1,10 @@
+error: this import is redundant
+  --> $DIR/single_component_path_imports.rs:6:1
+   |
+LL | use regex;
+   | ^^^^^^^^^^ help: remove it entirely
+   |
+   = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
new file mode 100644
index 00000000000..1c55af5dfb6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -0,0 +1,95 @@
+#![warn(clippy::single_match)]
+
+fn dummy() {}
+
+fn single_match() {
+    let x = Some(1u8);
+
+    match x {
+        Some(y) => {
+            println!("{:?}", y);
+        },
+        _ => (),
+    };
+
+    let x = Some(1u8);
+    match x {
+        // Note the missing block braces.
+        // We suggest `if let Some(y) = x { .. }` because the macro
+        // is expanded before we can do anything.
+        Some(y) => println!("{:?}", y),
+        _ => (),
+    }
+
+    let z = (1u8, 1u8);
+    match z {
+        (2..=3, 7..=9) => dummy(),
+        _ => {},
+    };
+
+    // Not linted (pattern guards used)
+    match x {
+        Some(y) if y == 0 => println!("{:?}", y),
+        _ => (),
+    }
+
+    // Not linted (no block with statements in the single arm)
+    match z {
+        (2..=3, 7..=9) => println!("{:?}", z),
+        _ => println!("nope"),
+    }
+}
+
+enum Foo {
+    Bar,
+    Baz(u8),
+}
+use std::borrow::Cow;
+use Foo::*;
+
+fn single_match_know_enum() {
+    let x = Some(1u8);
+    let y: Result<_, i8> = Ok(1i8);
+
+    match x {
+        Some(y) => dummy(),
+        None => (),
+    };
+
+    match y {
+        Ok(y) => dummy(),
+        Err(..) => (),
+    };
+
+    let c = Cow::Borrowed("");
+
+    match c {
+        Cow::Borrowed(..) => dummy(),
+        Cow::Owned(..) => (),
+    };
+
+    let z = Foo::Bar;
+    // no warning
+    match z {
+        Bar => println!("42"),
+        Baz(_) => (),
+    }
+
+    match z {
+        Baz(_) => println!("42"),
+        Bar => (),
+    }
+}
+
+macro_rules! single_match {
+    ($num:literal) => {
+        match $num {
+            15 => println!("15"),
+            _ => (),
+        }
+    };
+}
+
+fn main() {
+    single_match!(5);
+}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
new file mode 100644
index 00000000000..f69554d75f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -0,0 +1,69 @@
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:8:5
+   |
+LL | /     match x {
+LL | |         Some(y) => {
+LL | |             println!("{:?}", y);
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
+   |
+   = note: `-D clippy::single-match` implied by `-D warnings`
+help: try this
+   |
+LL |     if let Some(y) = x {
+LL |         println!("{:?}", y);
+LL |     };
+   |
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:16:5
+   |
+LL | /     match x {
+LL | |         // Note the missing block braces.
+LL | |         // We suggest `if let Some(y) = x { .. }` because the macro
+LL | |         // is expanded before we can do anything.
+LL | |         Some(y) => println!("{:?}", y),
+LL | |         _ => (),
+LL | |     }
+   | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }`
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:25:5
+   |
+LL | /     match z {
+LL | |         (2..=3, 7..=9) => dummy(),
+LL | |         _ => {},
+LL | |     };
+   | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:54:5
+   |
+LL | /     match x {
+LL | |         Some(y) => dummy(),
+LL | |         None => (),
+LL | |     };
+   | |_____^ help: try this: `if let Some(y) = x { dummy() }`
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:59:5
+   |
+LL | /     match y {
+LL | |         Ok(y) => dummy(),
+LL | |         Err(..) => (),
+LL | |     };
+   | |_____^ help: try this: `if let Ok(y) = y { dummy() }`
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:66:5
+   |
+LL | /     match c {
+LL | |         Cow::Borrowed(..) => dummy(),
+LL | |         Cow::Owned(..) => (),
+LL | |     };
+   | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
new file mode 100644
index 00000000000..34193be0b75
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::single_match_else)]
+
+enum ExprNode {
+    ExprAddrOf,
+    Butterflies,
+    Unicorns,
+}
+
+static NODE: ExprNode = ExprNode::Unicorns;
+
+fn unwrap_addr() -> Option<&'static ExprNode> {
+    match ExprNode::Butterflies {
+        ExprNode::ExprAddrOf => Some(&NODE),
+        _ => {
+            let x = 5;
+            None
+        },
+    }
+}
+
+macro_rules! unwrap_addr {
+    ($expression:expr) => {
+        match $expression {
+            ExprNode::ExprAddrOf => Some(&NODE),
+            _ => {
+                let x = 5;
+                None
+            },
+        }
+    };
+}
+
+fn main() {
+    unwrap_addr!(ExprNode::Unicorns);
+}
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
new file mode 100644
index 00000000000..59861d46eb3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -0,0 +1,23 @@
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:12:5
+   |
+LL | /     match ExprNode::Butterflies {
+LL | |         ExprNode::ExprAddrOf => Some(&NODE),
+LL | |         _ => {
+LL | |             let x = 5;
+LL | |             None
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::single-match-else` implied by `-D warnings`
+help: try this
+   |
+LL |     if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
+LL |         let x = 5;
+LL |         None
+LL |     }
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs
new file mode 100644
index 00000000000..a522c0f08b2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/skip_while_next.rs
@@ -0,0 +1,29 @@
+// aux-build:option_helpers.rs
+
+#![warn(clippy::skip_while_next)]
+#![allow(clippy::blacklisted_name)]
+
+extern crate option_helpers;
+use option_helpers::IteratorFalsePositives;
+
+#[rustfmt::skip]
+fn skip_while_next() {
+    let v = vec![3, 2, 1, 0, -1, -2, -3];
+
+    // Single-line case.
+    let _ = v.iter().skip_while(|&x| *x < 0).next();
+
+    // Multi-line case.
+    let _ = v.iter().skip_while(|&x| {
+                                *x < 0
+                            }
+                   ).next();
+
+    // Check that hat we don't lint if the caller is not an `Iterator`.
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.skip_while().next();
+}
+
+fn main() {
+    skip_while_next();
+}
diff --git a/src/tools/clippy/tests/ui/skip_while_next.stderr b/src/tools/clippy/tests/ui/skip_while_next.stderr
new file mode 100644
index 00000000000..a6b7bcd63ff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/skip_while_next.stderr
@@ -0,0 +1,23 @@
+error: called `skip_while(p).next()` on an `Iterator`
+  --> $DIR/skip_while_next.rs:14:13
+   |
+LL |     let _ = v.iter().skip_while(|&x| *x < 0).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::skip-while-next` implied by `-D warnings`
+   = help: this is more succinctly expressed by calling `.find(!p)` instead
+
+error: called `skip_while(p).next()` on an `Iterator`
+  --> $DIR/skip_while_next.rs:17:13
+   |
+LL |       let _ = v.iter().skip_while(|&x| {
+   |  _____________^
+LL | |                                 *x < 0
+LL | |                             }
+LL | |                    ).next();
+   | |___________________________^
+   |
+   = help: this is more succinctly expressed by calling `.find(!p)` instead
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
new file mode 100644
index 00000000000..c5ae3ff769b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -0,0 +1,63 @@
+use std::iter::repeat;
+
+fn main() {
+    resize_vector();
+    extend_vector();
+    mixed_extend_resize_vector();
+}
+
+fn extend_vector() {
+    // Extend with constant expression
+    let len = 300;
+    let mut vec1 = Vec::with_capacity(len);
+    vec1.extend(repeat(0).take(len));
+
+    // Extend with len expression
+    let mut vec2 = Vec::with_capacity(len - 10);
+    vec2.extend(repeat(0).take(len - 10));
+
+    // Extend with mismatching expression should not be warned
+    let mut vec3 = Vec::with_capacity(24322);
+    vec3.extend(repeat(0).take(2));
+}
+
+fn mixed_extend_resize_vector() {
+    // Mismatching len
+    let mut mismatching_len = Vec::with_capacity(30);
+    mismatching_len.extend(repeat(0).take(40));
+
+    // Slow initialization
+    let mut resized_vec = Vec::with_capacity(30);
+    resized_vec.resize(30, 0);
+
+    let mut extend_vec = Vec::with_capacity(30);
+    extend_vec.extend(repeat(0).take(30));
+}
+
+fn resize_vector() {
+    // Resize with constant expression
+    let len = 300;
+    let mut vec1 = Vec::with_capacity(len);
+    vec1.resize(len, 0);
+
+    // Resize mismatch len
+    let mut vec2 = Vec::with_capacity(200);
+    vec2.resize(10, 0);
+
+    // Resize with len expression
+    let mut vec3 = Vec::with_capacity(len - 10);
+    vec3.resize(len - 10, 0);
+
+    // Reinitialization should be warned
+    vec1 = Vec::with_capacity(10);
+    vec1.resize(10, 0);
+}
+
+fn do_stuff(vec: &mut Vec<u8>) {}
+
+fn extend_vector_with_manipulations_between() {
+    let len = 300;
+    let mut vec1: Vec<u8> = Vec::with_capacity(len);
+    do_stuff(&mut vec1);
+    vec1.extend(repeat(0).take(len));
+}
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
new file mode 100644
index 00000000000..5d2788ec260
--- /dev/null
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -0,0 +1,60 @@
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:13:5
+   |
+LL |     let mut vec1 = Vec::with_capacity(len);
+   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+LL |     vec1.extend(repeat(0).take(len));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:17:5
+   |
+LL |     let mut vec2 = Vec::with_capacity(len - 10);
+   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+LL |     vec2.extend(repeat(0).take(len - 10));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:31:5
+   |
+LL |     let mut resized_vec = Vec::with_capacity(30);
+   |                           ---------------------- help: consider replace allocation with: `vec![0; 30]`
+LL |     resized_vec.resize(30, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:34:5
+   |
+LL |     let mut extend_vec = Vec::with_capacity(30);
+   |                          ---------------------- help: consider replace allocation with: `vec![0; 30]`
+LL |     extend_vec.extend(repeat(0).take(30));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:41:5
+   |
+LL |     let mut vec1 = Vec::with_capacity(len);
+   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+LL |     vec1.resize(len, 0);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:49:5
+   |
+LL |     let mut vec3 = Vec::with_capacity(len - 10);
+   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+LL |     vec3.resize(len - 10, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:53:5
+   |
+LL |     vec1 = Vec::with_capacity(10);
+   |            ---------------------- help: consider replace allocation with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.fixed b/src/tools/clippy/tests/ui/starts_ends_with.fixed
new file mode 100644
index 00000000000..7dfcf9c91e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/starts_ends_with.fixed
@@ -0,0 +1,46 @@
+// run-rustfix
+#![allow(dead_code, unused_must_use)]
+
+fn main() {}
+
+#[allow(clippy::unnecessary_operation)]
+fn starts_with() {
+    "".starts_with(' ');
+    !"".starts_with(' ');
+}
+
+fn chars_cmp_with_unwrap() {
+    let s = String::from("foo");
+    if s.starts_with('f') {
+        // s.starts_with('f')
+        // Nothing here
+    }
+    if s.ends_with('o') {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if s.ends_with('o') {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if !s.starts_with('f') {
+        // !s.starts_with('f')
+        // Nothing here
+    }
+    if !s.ends_with('o') {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+    if !s.ends_with('o') {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn ends_with() {
+    "".ends_with(' ');
+    !"".ends_with(' ');
+    "".ends_with(' ');
+    !"".ends_with(' ');
+}
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.rs b/src/tools/clippy/tests/ui/starts_ends_with.rs
new file mode 100644
index 00000000000..e48a4246354
--- /dev/null
+++ b/src/tools/clippy/tests/ui/starts_ends_with.rs
@@ -0,0 +1,46 @@
+// run-rustfix
+#![allow(dead_code, unused_must_use)]
+
+fn main() {}
+
+#[allow(clippy::unnecessary_operation)]
+fn starts_with() {
+    "".chars().next() == Some(' ');
+    Some(' ') != "".chars().next();
+}
+
+fn chars_cmp_with_unwrap() {
+    let s = String::from("foo");
+    if s.chars().next().unwrap() == 'f' {
+        // s.starts_with('f')
+        // Nothing here
+    }
+    if s.chars().next_back().unwrap() == 'o' {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if s.chars().last().unwrap() == 'o' {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if s.chars().next().unwrap() != 'f' {
+        // !s.starts_with('f')
+        // Nothing here
+    }
+    if s.chars().next_back().unwrap() != 'o' {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+    if s.chars().last().unwrap() != 'o' {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn ends_with() {
+    "".chars().last() == Some(' ');
+    Some(' ') != "".chars().last();
+    "".chars().next_back() == Some(' ');
+    Some(' ') != "".chars().next_back();
+}
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.stderr b/src/tools/clippy/tests/ui/starts_ends_with.stderr
new file mode 100644
index 00000000000..7c726d0e010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/starts_ends_with.stderr
@@ -0,0 +1,78 @@
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:8:5
+   |
+LL |     "".chars().next() == Some(' ');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')`
+   |
+   = note: `-D clippy::chars-next-cmp` implied by `-D warnings`
+
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:9:5
+   |
+LL |     Some(' ') != "".chars().next();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')`
+
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:14:8
+   |
+LL |     if s.chars().next().unwrap() == 'f' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:18:8
+   |
+LL |     if s.chars().next_back().unwrap() == 'o' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
+   |
+   = note: `-D clippy::chars-last-cmp` implied by `-D warnings`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:22:8
+   |
+LL |     if s.chars().last().unwrap() == 'o' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
+
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:26:8
+   |
+LL |     if s.chars().next().unwrap() != 'f' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:30:8
+   |
+LL |     if s.chars().next_back().unwrap() != 'o' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:34:8
+   |
+LL |     if s.chars().last().unwrap() != 'o' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:42:5
+   |
+LL |     "".chars().last() == Some(' ');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:43:5
+   |
+LL |     Some(' ') != "".chars().last();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:44:5
+   |
+LL |     "".chars().next_back() == Some(' ');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:45:5
+   |
+LL |     Some(' ') != "".chars().next_back();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs
new file mode 100644
index 00000000000..30fd17c59e5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_add.rs
@@ -0,0 +1,26 @@
+// aux-build:macro_rules.rs
+
+#[macro_use]
+extern crate macro_rules;
+
+#[warn(clippy::string_add)]
+#[allow(clippy::string_add_assign, unused)]
+fn main() {
+    // ignores assignment distinction
+    let mut x = "".to_owned();
+
+    for _ in 1..3 {
+        x = x + ".";
+    }
+
+    let y = "".to_owned();
+    let z = y + "...";
+
+    assert_eq!(&x, &z);
+
+    let mut x = 1;
+    x = x + 1;
+    assert_eq!(2, x);
+
+    string_add!();
+}
diff --git a/src/tools/clippy/tests/ui/string_add.stderr b/src/tools/clippy/tests/ui/string_add.stderr
new file mode 100644
index 00000000000..3987641c75a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_add.stderr
@@ -0,0 +1,30 @@
+error: manual implementation of an assign operation
+  --> $DIR/string_add.rs:13:9
+   |
+LL |         x = x + ".";
+   |         ^^^^^^^^^^^ help: replace it with: `x += "."`
+   |
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
+
+error: you added something to a string. Consider using `String::push_str()` instead
+  --> $DIR/string_add.rs:13:13
+   |
+LL |         x = x + ".";
+   |             ^^^^^^^
+   |
+   = note: `-D clippy::string-add` implied by `-D warnings`
+
+error: you added something to a string. Consider using `String::push_str()` instead
+  --> $DIR/string_add.rs:17:13
+   |
+LL |     let z = y + "...";
+   |             ^^^^^^^^^
+
+error: manual implementation of an assign operation
+  --> $DIR/string_add.rs:22:5
+   |
+LL |     x = x + 1;
+   |     ^^^^^^^^^ help: replace it with: `x += 1`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/string_add_assign.fixed b/src/tools/clippy/tests/ui/string_add_assign.fixed
new file mode 100644
index 00000000000..db71bab1e52
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_add_assign.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#[allow(clippy::string_add, unused)]
+#[warn(clippy::string_add_assign)]
+fn main() {
+    // ignores assignment distinction
+    let mut x = "".to_owned();
+
+    for _ in 1..3 {
+        x += ".";
+    }
+
+    let y = "".to_owned();
+    let z = y + "...";
+
+    assert_eq!(&x, &z);
+
+    let mut x = 1;
+    x += 1;
+    assert_eq!(2, x);
+}
diff --git a/src/tools/clippy/tests/ui/string_add_assign.rs b/src/tools/clippy/tests/ui/string_add_assign.rs
new file mode 100644
index 00000000000..644991945cb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_add_assign.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#[allow(clippy::string_add, unused)]
+#[warn(clippy::string_add_assign)]
+fn main() {
+    // ignores assignment distinction
+    let mut x = "".to_owned();
+
+    for _ in 1..3 {
+        x = x + ".";
+    }
+
+    let y = "".to_owned();
+    let z = y + "...";
+
+    assert_eq!(&x, &z);
+
+    let mut x = 1;
+    x = x + 1;
+    assert_eq!(2, x);
+}
diff --git a/src/tools/clippy/tests/ui/string_add_assign.stderr b/src/tools/clippy/tests/ui/string_add_assign.stderr
new file mode 100644
index 00000000000..7676175c1b8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_add_assign.stderr
@@ -0,0 +1,24 @@
+error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead
+  --> $DIR/string_add_assign.rs:10:9
+   |
+LL |         x = x + ".";
+   |         ^^^^^^^^^^^
+   |
+   = note: `-D clippy::string-add-assign` implied by `-D warnings`
+
+error: manual implementation of an assign operation
+  --> $DIR/string_add_assign.rs:10:9
+   |
+LL |         x = x + ".";
+   |         ^^^^^^^^^^^ help: replace it with: `x += "."`
+   |
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
+
+error: manual implementation of an assign operation
+  --> $DIR/string_add_assign.rs:19:5
+   |
+LL |     x = x + 1;
+   |     ^^^^^^^^^ help: replace it with: `x += 1`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/string_extend.fixed b/src/tools/clippy/tests/ui/string_extend.fixed
new file mode 100644
index 00000000000..1883a9f8325
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_extend.fixed
@@ -0,0 +1,32 @@
+// run-rustfix
+
+#[derive(Copy, Clone)]
+struct HasChars;
+
+impl HasChars {
+    fn chars(self) -> std::str::Chars<'static> {
+        "HasChars".chars()
+    }
+}
+
+fn main() {
+    let abc = "abc";
+    let def = String::from("def");
+    let mut s = String::new();
+
+    s.push_str(abc);
+    s.push_str(abc);
+
+    s.push_str("abc");
+    s.push_str("abc");
+
+    s.push_str(&def);
+    s.push_str(&def);
+
+    s.extend(abc.chars().skip(1));
+    s.extend("abc".chars().skip(1));
+    s.extend(['a', 'b', 'c'].iter());
+
+    let f = HasChars;
+    s.extend(f.chars());
+}
diff --git a/src/tools/clippy/tests/ui/string_extend.rs b/src/tools/clippy/tests/ui/string_extend.rs
new file mode 100644
index 00000000000..07d0baa1be6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_extend.rs
@@ -0,0 +1,32 @@
+// run-rustfix
+
+#[derive(Copy, Clone)]
+struct HasChars;
+
+impl HasChars {
+    fn chars(self) -> std::str::Chars<'static> {
+        "HasChars".chars()
+    }
+}
+
+fn main() {
+    let abc = "abc";
+    let def = String::from("def");
+    let mut s = String::new();
+
+    s.push_str(abc);
+    s.extend(abc.chars());
+
+    s.push_str("abc");
+    s.extend("abc".chars());
+
+    s.push_str(&def);
+    s.extend(def.chars());
+
+    s.extend(abc.chars().skip(1));
+    s.extend("abc".chars().skip(1));
+    s.extend(['a', 'b', 'c'].iter());
+
+    let f = HasChars;
+    s.extend(f.chars());
+}
diff --git a/src/tools/clippy/tests/ui/string_extend.stderr b/src/tools/clippy/tests/ui/string_extend.stderr
new file mode 100644
index 00000000000..6af8c9e1662
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_extend.stderr
@@ -0,0 +1,22 @@
+error: calling `.extend(_.chars())`
+  --> $DIR/string_extend.rs:18:5
+   |
+LL |     s.extend(abc.chars());
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)`
+   |
+   = note: `-D clippy::string-extend-chars` implied by `-D warnings`
+
+error: calling `.extend(_.chars())`
+  --> $DIR/string_extend.rs:21:5
+   |
+LL |     s.extend("abc".chars());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")`
+
+error: calling `.extend(_.chars())`
+  --> $DIR/string_extend.rs:24:5
+   |
+LL |     s.extend(def.chars());
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)`
+
+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
new file mode 100644
index 00000000000..7ad272ade5f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::string_lit_as_bytes)]
+
+fn str_lit_as_bytes() {
+    let bs = b"hello there";
+
+    let bs = br###"raw string with 3# plus " ""###;
+
+    // no warning, because these cannot be written as byte string literals:
+    let ubs = "☃".as_bytes();
+    let ubs = "hello there! this is a very long string".as_bytes();
+
+    let strify = stringify!(foobar).as_bytes();
+
+    let includestr = include_bytes!("entry_unfixable.rs");
+
+    let _ = b"string with newline\t\n";
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
new file mode 100644
index 00000000000..1bf4538b7c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::string_lit_as_bytes)]
+
+fn str_lit_as_bytes() {
+    let bs = "hello there".as_bytes();
+
+    let bs = r###"raw string with 3# plus " ""###.as_bytes();
+
+    // no warning, because these cannot be written as byte string literals:
+    let ubs = "☃".as_bytes();
+    let ubs = "hello there! this is a very long string".as_bytes();
+
+    let strify = stringify!(foobar).as_bytes();
+
+    let includestr = include_str!("entry_unfixable.rs").as_bytes();
+
+    let _ = "string with newline\t\n".as_bytes();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
new file mode 100644
index 00000000000..ff6e3346dfc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
@@ -0,0 +1,28 @@
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:7:14
+   |
+LL |     let bs = "hello there".as_bytes();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
+   |
+   = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
+
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:9:14
+   |
+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
+   |
+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
+   |
+LL |     let _ = "string with newline/t/n".as_bytes();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/struct_excessive_bools.rs b/src/tools/clippy/tests/ui/struct_excessive_bools.rs
new file mode 100644
index 00000000000..ce4fe830a0a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_excessive_bools.rs
@@ -0,0 +1,44 @@
+#![warn(clippy::struct_excessive_bools)]
+
+macro_rules! foo {
+    () => {
+        struct MacroFoo {
+            a: bool,
+            b: bool,
+            c: bool,
+            d: bool,
+        }
+    };
+}
+
+foo!();
+
+struct Foo {
+    a: bool,
+    b: bool,
+    c: bool,
+}
+
+struct BadFoo {
+    a: bool,
+    b: bool,
+    c: bool,
+    d: bool,
+}
+
+#[repr(C)]
+struct Bar {
+    a: bool,
+    b: bool,
+    c: bool,
+    d: bool,
+}
+
+fn main() {
+    struct FooFoo {
+        a: bool,
+        b: bool,
+        c: bool,
+        d: bool,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/struct_excessive_bools.stderr b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr
new file mode 100644
index 00000000000..2941bf2983a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr
@@ -0,0 +1,29 @@
+error: more than 3 bools in a struct
+  --> $DIR/struct_excessive_bools.rs:22:1
+   |
+LL | / struct BadFoo {
+LL | |     a: bool,
+LL | |     b: bool,
+LL | |     c: bool,
+LL | |     d: bool,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::struct-excessive-bools` implied by `-D warnings`
+   = help: consider using a state machine or refactoring bools into two-variant enums
+
+error: more than 3 bools in a struct
+  --> $DIR/struct_excessive_bools.rs:38:5
+   |
+LL | /     struct FooFoo {
+LL | |         a: bool,
+LL | |         b: bool,
+LL | |         c: bool,
+LL | |         d: bool,
+LL | |     }
+   | |_____^
+   |
+   = help: consider using a state machine or refactoring bools into two-variant enums
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
new file mode 100644
index 00000000000..1f5b9811887
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
@@ -0,0 +1,90 @@
+#![warn(clippy::suspicious_arithmetic_impl)]
+use std::ops::{Add, AddAssign, BitOrAssign, Div, DivAssign, Mul, MulAssign, Sub};
+
+#[derive(Copy, Clone)]
+struct Foo(u32);
+
+impl Add for Foo {
+    type Output = Foo;
+
+    fn add(self, other: Self) -> Self {
+        Foo(self.0 - other.0)
+    }
+}
+
+impl AddAssign for Foo {
+    fn add_assign(&mut self, other: Foo) {
+        *self = *self - other;
+    }
+}
+
+impl BitOrAssign for Foo {
+    fn bitor_assign(&mut self, other: Foo) {
+        let idx = other.0;
+        self.0 |= 1 << idx; // OK: BinOpKind::Shl part of AssignOp as child node
+    }
+}
+
+impl MulAssign for Foo {
+    fn mul_assign(&mut self, other: Foo) {
+        self.0 /= other.0;
+    }
+}
+
+impl DivAssign for Foo {
+    fn div_assign(&mut self, other: Foo) {
+        self.0 /= other.0; // OK: BinOpKind::Div == DivAssign
+    }
+}
+
+impl Mul for Foo {
+    type Output = Foo;
+
+    fn mul(self, other: Foo) -> Foo {
+        Foo(self.0 * other.0 % 42) // OK: BinOpKind::Rem part of BiExpr as parent node
+    }
+}
+
+impl Sub for Foo {
+    type Output = Foo;
+
+    fn sub(self, other: Self) -> Self {
+        Foo(self.0 * other.0 - 42) // OK: BinOpKind::Mul part of BiExpr as child node
+    }
+}
+
+impl Div for Foo {
+    type Output = Foo;
+
+    fn div(self, other: Self) -> Self {
+        Foo(do_nothing(self.0 + other.0) / 42) // OK: BinOpKind::Add part of BiExpr as child node
+    }
+}
+
+struct Bar(i32);
+
+impl Add for Bar {
+    type Output = Bar;
+
+    fn add(self, other: Self) -> Self {
+        Bar(self.0 & !other.0) // OK: UnNot part of BiExpr as child node
+    }
+}
+
+impl Sub for Bar {
+    type Output = Bar;
+
+    fn sub(self, other: Self) -> Self {
+        if self.0 <= other.0 {
+            Bar(-(self.0 & other.0)) // OK: UnNeg part of BiExpr as parent node
+        } else {
+            Bar(0)
+        }
+    }
+}
+
+fn main() {}
+
+fn do_nothing(x: u32) -> u32 {
+    x
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
new file mode 100644
index 00000000000..7e42d72c30b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
@@ -0,0 +1,24 @@
+error: Suspicious use of binary operator in `Add` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:11:20
+   |
+LL |         Foo(self.0 - other.0)
+   |                    ^
+   |
+   = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings`
+
+error: Suspicious use of binary operator in `AddAssign` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:17:23
+   |
+LL |         *self = *self - other;
+   |                       ^
+   |
+   = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default
+
+error: Suspicious use of binary operator in `MulAssign` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:30:16
+   |
+LL |         self.0 /= other.0;
+   |                ^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_map.rs b/src/tools/clippy/tests/ui/suspicious_map.rs
new file mode 100644
index 00000000000..d838d8fde21
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_map.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::suspicious_map)]
+
+fn main() {
+    let _ = (0..3).map(|x| x + 2).count();
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_map.stderr b/src/tools/clippy/tests/ui/suspicious_map.stderr
new file mode 100644
index 00000000000..e1b4ba40376
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_map.stderr
@@ -0,0 +1,11 @@
+error: this call to `map()` won't have an effect on the call to `count()`
+  --> $DIR/suspicious_map.rs:4:13
+   |
+LL |     let _ = (0..3).map(|x| x + 2).count();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::suspicious-map` implied by `-D warnings`
+   = help: make sure you did not confuse `map` with `filter` or `for_each`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs
new file mode 100644
index 00000000000..9564e373c24
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::suspicious_unary_op_formatting)]
+
+#[rustfmt::skip]
+fn main() {
+    // weird binary operator formatting:
+    let a = 42;
+
+    if a >- 30 {}
+    if a >=- 30 {}
+
+    let b = true;
+    let c = false;
+
+    if b &&! c {}
+
+    if a >-   30 {}
+
+    // those are ok:
+    if a >-30 {}
+    if a < -30 {}
+    if b && !c {}
+    if a > -   30 {}
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr
new file mode 100644
index 00000000000..581527dcff8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr
@@ -0,0 +1,35 @@
+error: by not having a space between `>` and `-` it looks like `>-` is a single operator
+  --> $DIR/suspicious_unary_op_formatting.rs:8:9
+   |
+LL |     if a >- 30 {}
+   |         ^^^^
+   |
+   = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings`
+   = help: put a space between `>` and `-` and remove the space after `-`
+
+error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator
+  --> $DIR/suspicious_unary_op_formatting.rs:9:9
+   |
+LL |     if a >=- 30 {}
+   |         ^^^^^
+   |
+   = help: put a space between `>=` and `-` and remove the space after `-`
+
+error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator
+  --> $DIR/suspicious_unary_op_formatting.rs:14:9
+   |
+LL |     if b &&! c {}
+   |         ^^^^^
+   |
+   = help: put a space between `&&` and `!` and remove the space after `!`
+
+error: by not having a space between `>` and `-` it looks like `>-` is a single operator
+  --> $DIR/suspicious_unary_op_formatting.rs:16:9
+   |
+LL |     if a >-   30 {}
+   |         ^^^^^^
+   |
+   = help: put a space between `>` and `-` and remove the space after `-`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
new file mode 100644
index 00000000000..0f8f839a0d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -0,0 +1,83 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::no_effect,
+    clippy::redundant_clone,
+    redundant_semicolons,
+    unused_assignments
+)]
+
+struct Foo(u32);
+
+#[derive(Clone)]
+struct Bar {
+    a: u32,
+    b: u32,
+}
+
+fn field() {
+    let mut bar = Bar { a: 1, b: 2 };
+
+    let temp = bar.a;
+    bar.a = bar.b;
+    bar.b = temp;
+
+    let mut baz = vec![bar.clone(), bar.clone()];
+    let temp = baz[0].a;
+    baz[0].a = baz[1].a;
+    baz[1].a = temp;
+}
+
+fn array() {
+    let mut foo = [1, 2];
+    foo.swap(0, 1);
+
+    foo.swap(0, 1);
+}
+
+fn slice() {
+    let foo = &mut [1, 2];
+    foo.swap(0, 1);
+
+    foo.swap(0, 1);
+}
+
+fn unswappable_slice() {
+    let foo = &mut [vec![1, 2], vec![3, 4]];
+    let temp = foo[0][1];
+    foo[0][1] = foo[1][0];
+    foo[1][0] = temp;
+
+    // swap(foo[0][1], foo[1][0]) would fail
+}
+
+fn vec() {
+    let mut foo = vec![1, 2];
+    foo.swap(0, 1);
+
+    foo.swap(0, 1);
+}
+
+#[rustfmt::skip]
+fn main() {
+    field();
+    array();
+    slice();
+    unswappable_slice();
+    vec();
+
+    let mut a = 42;
+    let mut b = 1337;
+
+    std::mem::swap(&mut a, &mut b);
+
+    ; std::mem::swap(&mut a, &mut b);
+
+    let mut c = Foo(42);
+
+    std::mem::swap(&mut c.0, &mut a);
+
+    ; std::mem::swap(&mut c.0, &mut a);
+}
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
new file mode 100644
index 00000000000..5763d9e82d4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -0,0 +1,95 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::no_effect,
+    clippy::redundant_clone,
+    redundant_semicolons,
+    unused_assignments
+)]
+
+struct Foo(u32);
+
+#[derive(Clone)]
+struct Bar {
+    a: u32,
+    b: u32,
+}
+
+fn field() {
+    let mut bar = Bar { a: 1, b: 2 };
+
+    let temp = bar.a;
+    bar.a = bar.b;
+    bar.b = temp;
+
+    let mut baz = vec![bar.clone(), bar.clone()];
+    let temp = baz[0].a;
+    baz[0].a = baz[1].a;
+    baz[1].a = temp;
+}
+
+fn array() {
+    let mut foo = [1, 2];
+    let temp = foo[0];
+    foo[0] = foo[1];
+    foo[1] = temp;
+
+    foo.swap(0, 1);
+}
+
+fn slice() {
+    let foo = &mut [1, 2];
+    let temp = foo[0];
+    foo[0] = foo[1];
+    foo[1] = temp;
+
+    foo.swap(0, 1);
+}
+
+fn unswappable_slice() {
+    let foo = &mut [vec![1, 2], vec![3, 4]];
+    let temp = foo[0][1];
+    foo[0][1] = foo[1][0];
+    foo[1][0] = temp;
+
+    // swap(foo[0][1], foo[1][0]) would fail
+}
+
+fn vec() {
+    let mut foo = vec![1, 2];
+    let temp = foo[0];
+    foo[0] = foo[1];
+    foo[1] = temp;
+
+    foo.swap(0, 1);
+}
+
+#[rustfmt::skip]
+fn main() {
+    field();
+    array();
+    slice();
+    unswappable_slice();
+    vec();
+
+    let mut a = 42;
+    let mut b = 1337;
+
+    a = b;
+    b = a;
+
+    ; let t = a;
+    a = b;
+    b = t;
+
+    let mut c = Foo(42);
+
+    c.0 = a;
+    a = c.0;
+
+    ; let t = c.0;
+    c.0 = a;
+    a = t;
+}
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
new file mode 100644
index 00000000000..f49bcfedf3a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -0,0 +1,69 @@
+error: this looks like you are swapping elements of `foo` manually
+  --> $DIR/swap.rs:35:5
+   |
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
+   | |_________________^ help: try: `foo.swap(0, 1)`
+   |
+   = note: `-D clippy::manual-swap` implied by `-D warnings`
+
+error: this looks like you are swapping elements of `foo` manually
+  --> $DIR/swap.rs:44:5
+   |
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
+   | |_________________^ help: try: `foo.swap(0, 1)`
+
+error: this looks like you are swapping elements of `foo` manually
+  --> $DIR/swap.rs:62:5
+   |
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
+   | |_________________^ help: try: `foo.swap(0, 1)`
+
+error: this looks like you are swapping `a` and `b` manually
+  --> $DIR/swap.rs:83:7
+   |
+LL |       ; let t = a;
+   |  _______^
+LL | |     a = b;
+LL | |     b = t;
+   | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are swapping `c.0` and `a` manually
+  --> $DIR/swap.rs:92:7
+   |
+LL |       ; let t = c.0;
+   |  _______^
+LL | |     c.0 = a;
+LL | |     a = t;
+   | |_________^ help: try: `std::mem::swap(&mut c.0, &mut a)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `a` and `b`
+  --> $DIR/swap.rs:80:5
+   |
+LL | /     a = b;
+LL | |     b = a;
+   | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
+   |
+   = note: `-D clippy::almost-swapped` implied by `-D warnings`
+   = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `c.0` and `a`
+  --> $DIR/swap.rs:89:5
+   |
+LL | /     c.0 = a;
+LL | |     a = c.0;
+   | |___________^ help: try: `std::mem::swap(&mut c.0, &mut a)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed
new file mode 100644
index 00000000000..4bc4bc86c76
--- /dev/null
+++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![warn(clippy::tabs_in_doc_comments)]
+#[allow(dead_code)]
+
+///
+/// Struct to hold two strings:
+///     - first        one
+///     - second    one
+pub struct DoubleString {
+    ///
+    ///     - First String:
+    ///         - needs to be inside here
+    first_string: String,
+    ///
+    ///     - Second String:
+    ///         - needs to be inside here
+    second_string: String,
+}
+
+/// This is main
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs
new file mode 100644
index 00000000000..9db3416e659
--- /dev/null
+++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![warn(clippy::tabs_in_doc_comments)]
+#[allow(dead_code)]
+
+///
+/// Struct to hold two strings:
+/// 	- first		one
+/// 	- second	one
+pub struct DoubleString {
+    ///
+    /// 	- First String:
+    /// 		- needs to be inside here
+    first_string: String,
+    ///
+    /// 	- Second String:
+    /// 		- needs to be inside here
+    second_string: String,
+}
+
+/// This is main
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr
new file mode 100644
index 00000000000..355f2e80579
--- /dev/null
+++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr
@@ -0,0 +1,52 @@
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:12:9
+   |
+LL |     ///     - First String:
+   |         ^^^^ help: consider using four spaces per tab
+   |
+   = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings`
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:13:9
+   |
+LL |     ///         - needs to be inside here
+   |         ^^^^^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:16:9
+   |
+LL |     ///     - Second String:
+   |         ^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:17:9
+   |
+LL |     ///         - needs to be inside here
+   |         ^^^^^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:8:5
+   |
+LL | ///     - first        one
+   |     ^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:8:13
+   |
+LL | ///     - first        one
+   |                ^^^^^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:9:5
+   |
+LL | ///     - second    one
+   |     ^^^^ help: consider using four spaces per tab
+
+error: using tabs in doc comments is not recommended
+  --> $DIR/tabs_in_doc_comments.rs:9:14
+   |
+LL | ///     - second    one
+   |                 ^^^^ help: consider using four spaces per tab
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/temporary_assignment.rs b/src/tools/clippy/tests/ui/temporary_assignment.rs
new file mode 100644
index 00000000000..c6c315d5fab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/temporary_assignment.rs
@@ -0,0 +1,75 @@
+#![warn(clippy::temporary_assignment)]
+
+use std::ops::{Deref, DerefMut};
+
+struct TupleStruct(i32);
+
+struct Struct {
+    field: i32,
+}
+
+struct MultiStruct {
+    structure: Struct,
+}
+
+struct Wrapper<'a> {
+    inner: &'a mut Struct,
+}
+
+impl<'a> Deref for Wrapper<'a> {
+    type Target = Struct;
+    fn deref(&self) -> &Struct {
+        self.inner
+    }
+}
+
+impl<'a> DerefMut for Wrapper<'a> {
+    fn deref_mut(&mut self) -> &mut Struct {
+        self.inner
+    }
+}
+
+struct ArrayStruct {
+    array: [i32; 1],
+}
+
+const A: TupleStruct = TupleStruct(1);
+const B: Struct = Struct { field: 1 };
+const C: MultiStruct = MultiStruct {
+    structure: Struct { field: 1 },
+};
+const D: ArrayStruct = ArrayStruct { array: [1] };
+
+fn main() {
+    let mut s = Struct { field: 0 };
+    let mut t = (0, 0);
+
+    Struct { field: 0 }.field = 1;
+    MultiStruct {
+        structure: Struct { field: 0 },
+    }
+    .structure
+    .field = 1;
+    ArrayStruct { array: [0] }.array[0] = 1;
+    (0, 0).0 = 1;
+
+    A.0 = 2;
+    B.field = 2;
+    C.structure.field = 2;
+    D.array[0] = 2;
+
+    // no error
+    s.field = 1;
+    t.0 = 1;
+    Wrapper { inner: &mut s }.field = 1;
+    let mut a_mut = TupleStruct(1);
+    a_mut.0 = 2;
+    let mut b_mut = Struct { field: 1 };
+    b_mut.field = 2;
+    let mut c_mut = MultiStruct {
+        structure: Struct { field: 1 },
+    };
+    c_mut.structure.field = 2;
+    let mut d_mut = ArrayStruct { array: [1] };
+    d_mut.array[0] = 2;
+}
diff --git a/src/tools/clippy/tests/ui/temporary_assignment.stderr b/src/tools/clippy/tests/ui/temporary_assignment.stderr
new file mode 100644
index 00000000000..4efe2d4bb67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/temporary_assignment.stderr
@@ -0,0 +1,56 @@
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:47:5
+   |
+LL |     Struct { field: 0 }.field = 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::temporary-assignment` implied by `-D warnings`
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:48:5
+   |
+LL | /     MultiStruct {
+LL | |         structure: Struct { field: 0 },
+LL | |     }
+LL | |     .structure
+LL | |     .field = 1;
+   | |______________^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:53:5
+   |
+LL |     ArrayStruct { array: [0] }.array[0] = 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:54:5
+   |
+LL |     (0, 0).0 = 1;
+   |     ^^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:56:5
+   |
+LL |     A.0 = 2;
+   |     ^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:57:5
+   |
+LL |     B.field = 2;
+   |     ^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:58:5
+   |
+LL |     C.structure.field = 2;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:59:5
+   |
+LL |     D.array[0] = 2;
+   |     ^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.fixed b/src/tools/clippy/tests/ui/to_digit_is_some.fixed
new file mode 100644
index 00000000000..19184df0bec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.fixed
@@ -0,0 +1,11 @@
+//run-rustfix
+
+#![warn(clippy::to_digit_is_some)]
+
+fn main() {
+    let c = 'x';
+    let d = &c;
+
+    let _ = d.is_digit(10);
+    let _ = char::is_digit(c, 10);
+}
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.rs b/src/tools/clippy/tests/ui/to_digit_is_some.rs
new file mode 100644
index 00000000000..45a6728ebf5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.rs
@@ -0,0 +1,11 @@
+//run-rustfix
+
+#![warn(clippy::to_digit_is_some)]
+
+fn main() {
+    let c = 'x';
+    let d = &c;
+
+    let _ = d.to_digit(10).is_some();
+    let _ = char::to_digit(c, 10).is_some();
+}
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.stderr b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
new file mode 100644
index 00000000000..177d3ccd3e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
@@ -0,0 +1,16 @@
+error: use of `.to_digit(..).is_some()`
+  --> $DIR/to_digit_is_some.rs:9:13
+   |
+LL |     let _ = d.to_digit(10).is_some();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(10)`
+   |
+   = note: `-D clippy::to-digit-is-some` implied by `-D warnings`
+
+error: use of `.to_digit(..).is_some()`
+  --> $DIR/to_digit_is_some.rs:10:13
+   |
+LL |     let _ = char::to_digit(c, 10).is_some();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 10)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
new file mode 100644
index 00000000000..33605aca019
--- /dev/null
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+
+#![warn(clippy::toplevel_ref_arg)]
+
+fn main() {
+    // Closures should not warn
+    let y = |ref x| println!("{:?}", x);
+    y(1u8);
+
+    let _x = &1;
+
+    let _y: &(&_, u8) = &(&1, 2);
+
+    let _z = &(1 + 2);
+
+    let _z = &mut (1 + 2);
+
+    let (ref x, _) = (1, 2); // ok, not top level
+    println!("The answer is {}.", x);
+
+    let _x = &vec![1, 2, 3];
+
+    // Make sure that allowing the lint works
+    #[allow(clippy::toplevel_ref_arg)]
+    let ref mut _x = 1_234_543;
+
+    // ok
+    for ref _x in 0..10 {}
+}
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
new file mode 100644
index 00000000000..59759f11893
--- /dev/null
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
@@ -0,0 +1,29 @@
+// run-rustfix
+
+#![warn(clippy::toplevel_ref_arg)]
+
+fn main() {
+    // Closures should not warn
+    let y = |ref x| println!("{:?}", x);
+    y(1u8);
+
+    let ref _x = 1;
+
+    let ref _y: (&_, u8) = (&1, 2);
+
+    let ref _z = 1 + 2;
+
+    let ref mut _z = 1 + 2;
+
+    let (ref x, _) = (1, 2); // ok, not top level
+    println!("The answer is {}.", x);
+
+    let ref _x = vec![1, 2, 3];
+
+    // Make sure that allowing the lint works
+    #[allow(clippy::toplevel_ref_arg)]
+    let ref mut _x = 1_234_543;
+
+    // ok
+    for ref _x in 0..10 {}
+}
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr
new file mode 100644
index 00000000000..19d69496709
--- /dev/null
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr
@@ -0,0 +1,34 @@
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:10:9
+   |
+LL |     let ref _x = 1;
+   |     ----^^^^^^----- help: try: `let _x = &1;`
+   |
+   = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
+
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:12:9
+   |
+LL |     let ref _y: (&_, u8) = (&1, 2);
+   |     ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);`
+
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:14:9
+   |
+LL |     let ref _z = 1 + 2;
+   |     ----^^^^^^--------- help: try: `let _z = &(1 + 2);`
+
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:16:9
+   |
+LL |     let ref mut _z = 1 + 2;
+   |     ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);`
+
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:21:9
+   |
+LL |     let ref _x = vec![1, 2, 3];
+   |     ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs
new file mode 100644
index 00000000000..42cac2ba4de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs
@@ -0,0 +1,11 @@
+#![warn(clippy::toplevel_ref_arg)]
+#![allow(unused)]
+
+fn the_answer(ref mut x: u8) {
+    *x = 42;
+}
+
+fn main() {
+    let mut x = 0;
+    the_answer(x);
+}
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
new file mode 100644
index 00000000000..295e2f35608
--- /dev/null
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
@@ -0,0 +1,10 @@
+error: `ref` directly on a function argument is ignored. Consider using a reference type instead.
+  --> $DIR/toplevel_ref_arg_non_rustfix.rs:4:15
+   |
+LL | fn the_answer(ref mut x: u8) {
+   |               ^^^^^^^^^
+   |
+   = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/trailing_zeros.rs b/src/tools/clippy/tests/ui/trailing_zeros.rs
new file mode 100644
index 00000000000..1cef8c2cfc9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trailing_zeros.rs
@@ -0,0 +1,9 @@
+#![allow(unused_parens)]
+
+fn main() {
+    let x: i32 = 42;
+    let _ = (x & 0b1111 == 0); // suggest trailing_zeros
+    let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
+    let _ = x & 0b1_1010 == 0; // do not lint
+    let _ = x & 1 == 0; // do not lint
+}
diff --git a/src/tools/clippy/tests/ui/trailing_zeros.stderr b/src/tools/clippy/tests/ui/trailing_zeros.stderr
new file mode 100644
index 00000000000..320d9cc3f64
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trailing_zeros.stderr
@@ -0,0 +1,16 @@
+error: bit mask could be simplified with a call to `trailing_zeros`
+  --> $DIR/trailing_zeros.rs:5:13
+   |
+LL |     let _ = (x & 0b1111 == 0); // suggest trailing_zeros
+   |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
+   |
+   = note: `-D clippy::verbose-bit-mask` implied by `-D warnings`
+
+error: bit mask could be simplified with a call to `trailing_zeros`
+  --> $DIR/trailing_zeros.rs:6:13
+   |
+LL |     let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
+   |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
new file mode 100644
index 00000000000..bb853d23704
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -0,0 +1,94 @@
+#![allow(dead_code)]
+
+extern crate core;
+
+use std::mem::transmute as my_transmute;
+use std::vec::Vec as MyVec;
+
+fn my_int() -> Usize {
+    Usize(42)
+}
+
+fn my_vec() -> MyVec<i32> {
+    vec![]
+}
+
+#[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
+#[warn(clippy::useless_transmute)]
+unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
+    let _: &'a T = core::intrinsics::transmute(t);
+
+    let _: &'a U = core::intrinsics::transmute(t);
+
+    let _: *const T = core::intrinsics::transmute(t);
+
+    let _: *mut T = core::intrinsics::transmute(t);
+
+    let _: *const U = core::intrinsics::transmute(t);
+}
+
+#[warn(clippy::useless_transmute)]
+fn useless() {
+    unsafe {
+        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
+
+        let _: Vec<i32> = core::mem::transmute(my_vec());
+
+        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
+
+        let _: Vec<i32> = std::mem::transmute(my_vec());
+
+        let _: Vec<i32> = my_transmute(my_vec());
+
+        let _: *const usize = std::mem::transmute(5_isize);
+
+        let _ = 5_isize as *const usize;
+
+        let _: *const usize = std::mem::transmute(1 + 1usize);
+
+        let _ = (1 + 1_usize) as *const usize;
+    }
+}
+
+struct Usize(usize);
+
+#[warn(clippy::crosspointer_transmute)]
+fn crosspointer() {
+    let mut int: Usize = Usize(0);
+    let int_const_ptr: *const Usize = &int as *const Usize;
+    let int_mut_ptr: *mut Usize = &mut int as *mut Usize;
+
+    unsafe {
+        let _: Usize = core::intrinsics::transmute(int_const_ptr);
+
+        let _: Usize = core::intrinsics::transmute(int_mut_ptr);
+
+        let _: *const Usize = core::intrinsics::transmute(my_int());
+
+        let _: *mut Usize = core::intrinsics::transmute(my_int());
+    }
+}
+
+#[warn(clippy::transmute_int_to_char)]
+fn int_to_char() {
+    let _: char = unsafe { std::mem::transmute(0_u32) };
+    let _: char = unsafe { std::mem::transmute(0_i32) };
+}
+
+#[warn(clippy::transmute_int_to_bool)]
+fn int_to_bool() {
+    let _: bool = unsafe { std::mem::transmute(0_u8) };
+}
+
+#[warn(clippy::transmute_int_to_float)]
+fn int_to_float() {
+    let _: f32 = unsafe { std::mem::transmute(0_u32) };
+    let _: f32 = unsafe { std::mem::transmute(0_i32) };
+}
+
+fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
+    let _: &str = unsafe { std::mem::transmute(b) };
+    let _: &mut str = unsafe { std::mem::transmute(mb) };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
new file mode 100644
index 00000000000..8582080498f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -0,0 +1,146 @@
+error: transmute from a type (`&T`) to itself
+  --> $DIR/transmute.rs:19:20
+   |
+LL |     let _: &'a T = core::intrinsics::transmute(t);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::useless-transmute` implied by `-D warnings`
+
+error: transmute from a reference to a pointer
+  --> $DIR/transmute.rs:23:23
+   |
+LL |     let _: *const T = core::intrinsics::transmute(t);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
+
+error: transmute from a reference to a pointer
+  --> $DIR/transmute.rs:25:21
+   |
+LL |     let _: *mut T = core::intrinsics::transmute(t);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
+
+error: transmute from a reference to a pointer
+  --> $DIR/transmute.rs:27:23
+   |
+LL |     let _: *const U = core::intrinsics::transmute(t);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
+
+error: transmute from a type (`std::vec::Vec<i32>`) to itself
+  --> $DIR/transmute.rs:33:27
+   |
+LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`std::vec::Vec<i32>`) to itself
+  --> $DIR/transmute.rs:35:27
+   |
+LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`std::vec::Vec<i32>`) to itself
+  --> $DIR/transmute.rs:37:27
+   |
+LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`std::vec::Vec<i32>`) to itself
+  --> $DIR/transmute.rs:39:27
+   |
+LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`std::vec::Vec<i32>`) to itself
+  --> $DIR/transmute.rs:41:27
+   |
+LL |         let _: Vec<i32> = my_transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from an integer to a pointer
+  --> $DIR/transmute.rs:43:31
+   |
+LL |         let _: *const usize = std::mem::transmute(5_isize);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
+
+error: transmute from an integer to a pointer
+  --> $DIR/transmute.rs:47:31
+   |
+LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
+
+error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
+  --> $DIR/transmute.rs:62:24
+   |
+LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
+
+error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
+  --> $DIR/transmute.rs:64:24
+   |
+LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
+  --> $DIR/transmute.rs:66:31
+   |
+LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
+  --> $DIR/transmute.rs:68:29
+   |
+LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a `u32` to a `char`
+  --> $DIR/transmute.rs:74:28
+   |
+LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
+   |
+   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
+
+error: transmute from a `i32` to a `char`
+  --> $DIR/transmute.rs:75:28
+   |
+LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
+
+error: transmute from a `u8` to a `bool`
+  --> $DIR/transmute.rs:80:28
+   |
+LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
+   |
+   = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
+
+error: transmute from a `u32` to a `f32`
+  --> $DIR/transmute.rs:85:27
+   |
+LL |     let _: f32 = unsafe { std::mem::transmute(0_u32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
+   |
+   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
+
+error: transmute from a `i32` to a `f32`
+  --> $DIR/transmute.rs:86:27
+   |
+LL |     let _: f32 = unsafe { std::mem::transmute(0_i32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
+
+error: transmute from a `&[u8]` to a `&str`
+  --> $DIR/transmute.rs:90:28
+   |
+LL |     let _: &str = unsafe { std::mem::transmute(b) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
+   |
+   = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
+
+error: transmute from a `&mut [u8]` to a `&mut str`
+  --> $DIR/transmute.rs:91:32
+   |
+LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
+
+error: aborting due to 22 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_32bit.rs b/src/tools/clippy/tests/ui/transmute_32bit.rs
new file mode 100644
index 00000000000..ffe22b12f55
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_32bit.rs
@@ -0,0 +1,14 @@
+// ignore-64bit
+
+#[warn(clippy::wrong_transmute)]
+fn main() {
+    unsafe {
+        let _: *const usize = std::mem::transmute(6.0f32);
+
+        let _: *mut usize = std::mem::transmute(6.0f32);
+
+        let _: *const usize = std::mem::transmute('x');
+
+        let _: *mut usize = std::mem::transmute('x');
+    }
+}
diff --git a/src/tools/clippy/tests/ui/transmute_32bit.stderr b/src/tools/clippy/tests/ui/transmute_32bit.stderr
new file mode 100644
index 00000000000..040519564b9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_32bit.stderr
@@ -0,0 +1,28 @@
+error: transmute from a `f32` to a pointer
+  --> $DIR/transmute_32bit.rs:6:31
+   |
+LL |         let _: *const usize = std::mem::transmute(6.0f32);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::wrong-transmute` implied by `-D warnings`
+
+error: transmute from a `f32` to a pointer
+  --> $DIR/transmute_32bit.rs:8:29
+   |
+LL |         let _: *mut usize = std::mem::transmute(6.0f32);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a `char` to a pointer
+  --> $DIR/transmute_32bit.rs:10:31
+   |
+LL |         let _: *const usize = std::mem::transmute('x');
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from a `char` to a pointer
+  --> $DIR/transmute_32bit.rs:12:29
+   |
+LL |         let _: *mut usize = std::mem::transmute('x');
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_64bit.rs b/src/tools/clippy/tests/ui/transmute_64bit.rs
new file mode 100644
index 00000000000..00dc0b2c360
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_64bit.rs
@@ -0,0 +1,10 @@
+// ignore-32bit
+
+#[warn(clippy::wrong_transmute)]
+fn main() {
+    unsafe {
+        let _: *const usize = std::mem::transmute(6.0f64);
+
+        let _: *mut usize = std::mem::transmute(6.0f64);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/transmute_64bit.stderr b/src/tools/clippy/tests/ui/transmute_64bit.stderr
new file mode 100644
index 00000000000..d1854c009ef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_64bit.stderr
@@ -0,0 +1,16 @@
+error: transmute from a `f64` to a pointer
+  --> $DIR/transmute_64bit.rs:6:31
+   |
+LL |         let _: *const usize = std::mem::transmute(6.0f64);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::wrong-transmute` implied by `-D warnings`
+
+error: transmute from a `f64` to a pointer
+  --> $DIR/transmute_64bit.rs:8:29
+   |
+LL |         let _: *mut usize = std::mem::transmute(6.0f64);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_collection.rs b/src/tools/clippy/tests/ui/transmute_collection.rs
new file mode 100644
index 00000000000..cd5a7127791
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_collection.rs
@@ -0,0 +1,47 @@
+#![warn(clippy::unsound_collection_transmute)]
+
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
+use std::mem::transmute;
+
+fn main() {
+    unsafe {
+        // wrong size
+        let _ = transmute::<_, Vec<u32>>(vec![0u8]);
+        // wrong layout
+        let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]);
+
+        // wrong size
+        let _ = transmute::<_, VecDeque<u32>>(VecDeque::<u8>::new());
+        // wrong layout
+        let _ = transmute::<_, VecDeque<u32>>(VecDeque::<[u8; 4]>::new());
+
+        // wrong size
+        let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<u8>::new());
+        // wrong layout
+        let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<[u8; 4]>::new());
+
+        // wrong size
+        let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<u8>::new());
+        // wrong layout
+        let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<[u8; 4]>::new());
+
+        // wrong size
+        let _ = transmute::<_, HashSet<u32>>(HashSet::<u8>::new());
+        // wrong layout
+        let _ = transmute::<_, HashSet<u32>>(HashSet::<[u8; 4]>::new());
+
+        // wrong size
+        let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, u8>::new());
+        let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u32, u32>::new());
+        // wrong layout
+        let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, [u8; 4]>::new());
+        let _ = transmute::<_, BTreeMap<u32, u32>>(BTreeMap::<[u8; 4], u32>::new());
+
+        // wrong size
+        let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, u8>::new());
+        let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u32, u32>::new());
+        // wrong layout
+        let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, [u8; 4]>::new());
+        let _ = transmute::<_, HashMap<u32, u32>>(HashMap::<[u8; 4], u32>::new());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/transmute_collection.stderr b/src/tools/clippy/tests/ui/transmute_collection.stderr
new file mode 100644
index 00000000000..ebc05c402ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_collection.stderr
@@ -0,0 +1,112 @@
+error: transmute from `std::vec::Vec<u8>` to `std::vec::Vec<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:9:17
+   |
+LL |         let _ = transmute::<_, Vec<u32>>(vec![0u8]);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unsound-collection-transmute` implied by `-D warnings`
+
+error: transmute from `std::vec::Vec<u32>` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:11:17
+   |
+LL |         let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::VecDeque<u8>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:14:17
+   |
+LL |         let _ = transmute::<_, VecDeque<u32>>(VecDeque::<u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:16:17
+   |
+LL |         let _ = transmute::<_, VecDeque<u32>>(VecDeque::<[u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BinaryHeap<u8>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:19:17
+   |
+LL |         let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BinaryHeap<[u8; 4]>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:21:17
+   |
+LL |         let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<[u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeSet<u8>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:24:17
+   |
+LL |         let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeSet<[u8; 4]>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:26:17
+   |
+LL |         let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<[u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashSet<u8>` to `std::collections::HashSet<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:29:17
+   |
+LL |         let _ = transmute::<_, HashSet<u32>>(HashSet::<u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections::HashSet<u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:31:17
+   |
+LL |         let _ = transmute::<_, HashSet<u32>>(HashSet::<[u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeMap<u8, u8>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:34:17
+   |
+LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeMap<u32, u32>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:35:17
+   |
+LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u32, u32>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeMap<u8, [u8; 4]>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:37:17
+   |
+LL |         let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, [u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap<u32, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:38:17
+   |
+LL |         let _ = transmute::<_, BTreeMap<u32, u32>>(BTreeMap::<[u8; 4], u32>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashMap<u8, u8>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:41:17
+   |
+LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, u8>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashMap<u32, u32>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:42:17
+   |
+LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u32, u32>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashMap<u8, [u8; 4]>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:44:17
+   |
+LL |         let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, [u8; 4]>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collections::HashMap<u32, u32>` with mismatched layout is unsound
+  --> $DIR/transmute_collection.rs:45:17
+   |
+LL |         let _ = transmute::<_, HashMap<u32, u32>>(HashMap::<[u8; 4], u32>::new());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 18 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
new file mode 100644
index 00000000000..ce942751ada
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
@@ -0,0 +1,12 @@
+#[warn(clippy::transmute_float_to_int)]
+
+fn float_to_int() {
+    let _: u32 = unsafe { std::mem::transmute(1f32) };
+    let _: i32 = unsafe { std::mem::transmute(1f32) };
+    let _: u64 = unsafe { std::mem::transmute(1f64) };
+    let _: i64 = unsafe { std::mem::transmute(1f64) };
+    let _: u64 = unsafe { std::mem::transmute(1.0) };
+    let _: u64 = unsafe { std::mem::transmute(-1.0) };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
new file mode 100644
index 00000000000..eb786bb39f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
@@ -0,0 +1,40 @@
+error: transmute from a `f32` to a `u32`
+  --> $DIR/transmute_float_to_int.rs:4:27
+   |
+LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
+   |
+   = note: `-D clippy::transmute-float-to-int` implied by `-D warnings`
+
+error: transmute from a `f32` to a `i32`
+  --> $DIR/transmute_float_to_int.rs:5:27
+   |
+LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
+
+error: transmute from a `f64` to a `u64`
+  --> $DIR/transmute_float_to_int.rs:6:27
+   |
+LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
+
+error: transmute from a `f64` to a `i64`
+  --> $DIR/transmute_float_to_int.rs:7:27
+   |
+LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
+
+error: transmute from a `f64` to a `u64`
+  --> $DIR/transmute_float_to_int.rs:8:27
+   |
+LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
+
+error: transmute from a `f64` to a `u64`
+  --> $DIR/transmute_float_to_int.rs:9:27
+   |
+LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
new file mode 100644
index 00000000000..0d8a322f2b2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
@@ -0,0 +1,54 @@
+#![warn(clippy::transmute_ptr_to_ptr)]
+
+// Make sure we can modify lifetimes, which is one of the recommended uses
+// of transmute
+
+// Make sure we can do static lifetime transmutes
+unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
+    std::mem::transmute::<&'a T, &'static T>(t)
+}
+
+// Make sure we can do non-static lifetime transmutes
+unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
+    std::mem::transmute::<&'a T, &'b T>(t)
+}
+
+struct LifetimeParam<'a> {
+    s: &'a str,
+}
+
+struct GenericParam<T> {
+    t: T,
+}
+
+fn transmute_ptr_to_ptr() {
+    let ptr = &1u32 as *const u32;
+    let mut_ptr = &mut 1u32 as *mut u32;
+    unsafe {
+        // pointer-to-pointer transmutes; bad
+        let _: *const f32 = std::mem::transmute(ptr);
+        let _: *mut f32 = std::mem::transmute(mut_ptr);
+        // ref-ref transmutes; bad
+        let _: &f32 = std::mem::transmute(&1u32);
+        let _: &f64 = std::mem::transmute(&1f32);
+        // ^ this test is here because both f32 and f64 are the same TypeVariant, but they are not
+        // the same type
+        let _: &mut f32 = std::mem::transmute(&mut 1u32);
+        let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
+    }
+
+    // these are recommendations for solving the above; if these lint we need to update
+    // those suggestions
+    let _ = ptr as *const f32;
+    let _ = mut_ptr as *mut f32;
+    let _ = unsafe { &*(&1u32 as *const u32 as *const f32) };
+    let _ = unsafe { &mut *(&mut 1u32 as *mut u32 as *mut f32) };
+
+    // transmute internal lifetimes, should not lint
+    let s = "hello world".to_owned();
+    let lp = LifetimeParam { s: &s };
+    let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
+    let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr
new file mode 100644
index 00000000000..4d1b8fcc199
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr
@@ -0,0 +1,40 @@
+error: transmute from a pointer to a pointer
+  --> $DIR/transmute_ptr_to_ptr.rs:29:29
+   |
+LL |         let _: *const f32 = std::mem::transmute(ptr);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32`
+   |
+   = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
+
+error: transmute from a pointer to a pointer
+  --> $DIR/transmute_ptr_to_ptr.rs:30:27
+   |
+LL |         let _: *mut f32 = std::mem::transmute(mut_ptr);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32`
+
+error: transmute from a reference to a reference
+  --> $DIR/transmute_ptr_to_ptr.rs:32:23
+   |
+LL |         let _: &f32 = std::mem::transmute(&1u32);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`
+
+error: transmute from a reference to a reference
+  --> $DIR/transmute_ptr_to_ptr.rs:33:23
+   |
+LL |         let _: &f64 = std::mem::transmute(&1f32);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`
+
+error: transmute from a reference to a reference
+  --> $DIR/transmute_ptr_to_ptr.rs:36:27
+   |
+LL |         let _: &mut f32 = std::mem::transmute(&mut 1u32);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`
+
+error: transmute from a reference to a reference
+  --> $DIR/transmute_ptr_to_ptr.rs:37:37
+   |
+LL |         let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
new file mode 100644
index 00000000000..ba35c6adc4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -0,0 +1,41 @@
+#![warn(clippy::transmute_ptr_to_ref)]
+
+unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+    let _: &T = std::mem::transmute(p);
+    let _: &T = &*p;
+
+    let _: &mut T = std::mem::transmute(m);
+    let _: &mut T = &mut *m;
+
+    let _: &T = std::mem::transmute(m);
+    let _: &T = &*m;
+
+    let _: &mut T = std::mem::transmute(p as *mut T);
+    let _ = &mut *(p as *mut T);
+
+    let _: &T = std::mem::transmute(o);
+    let _: &T = &*(o as *const T);
+
+    let _: &mut T = std::mem::transmute(om);
+    let _: &mut T = &mut *(om as *mut T);
+
+    let _: &T = std::mem::transmute(om);
+    let _: &T = &*(om as *const T);
+}
+
+fn issue1231() {
+    struct Foo<'a, T> {
+        bar: &'a T,
+    }
+
+    let raw = 42 as *const i32;
+    let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
+
+    let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
+
+    type Bar<'a> = &'a u8;
+    let raw = 42 as *const i32;
+    unsafe { std::mem::transmute::<_, Bar>(raw) };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
new file mode 100644
index 00000000000..df0598a58cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -0,0 +1,64 @@
+error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
+  --> $DIR/transmute_ptr_to_ref.rs:4:17
+   |
+LL |     let _: &T = std::mem::transmute(p);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
+   |
+   = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
+
+error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
+  --> $DIR/transmute_ptr_to_ref.rs:7:21
+   |
+LL |     let _: &mut T = std::mem::transmute(m);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
+
+error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
+  --> $DIR/transmute_ptr_to_ref.rs:10:17
+   |
+LL |     let _: &T = std::mem::transmute(m);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
+
+error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
+  --> $DIR/transmute_ptr_to_ref.rs:13:21
+   |
+LL |     let _: &mut T = std::mem::transmute(p as *mut T);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
+
+error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
+  --> $DIR/transmute_ptr_to_ref.rs:16:17
+   |
+LL |     let _: &T = std::mem::transmute(o);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
+
+error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
+  --> $DIR/transmute_ptr_to_ref.rs:19:21
+   |
+LL |     let _: &mut T = std::mem::transmute(om);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
+
+error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
+  --> $DIR/transmute_ptr_to_ref.rs:22:17
+   |
+LL |     let _: &T = std::mem::transmute(om);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
+
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<u8>`)
+  --> $DIR/transmute_ptr_to_ref.rs:32:32
+   |
+LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)`
+
+error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<&u8>`)
+  --> $DIR/transmute_ptr_to_ref.rs:34:33
+   |
+LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)`
+
+error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
+  --> $DIR/transmute_ptr_to_ref.rs:38:14
+   |
+LL |     unsafe { std::mem::transmute::<_, Bar>(raw) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs
new file mode 100644
index 00000000000..ea3ee8edc81
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmuting_null.rs
@@ -0,0 +1,30 @@
+#![allow(dead_code)]
+#![warn(clippy::transmuting_null)]
+#![allow(clippy::zero_ptr)]
+#![allow(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::eq_op)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+    unsafe {
+        let _: &u64 = std::mem::transmute(0 as *const u64);
+        let _: &u64 = std::mem::transmute(std::ptr::null::<u64>());
+    }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+    unsafe {
+        // Should raise a lint.
+        let _: &u64 = std::mem::transmute(ZPTR);
+        // Should NOT raise a lint.
+        let _: &u64 = std::mem::transmute(NOT_ZPTR);
+    }
+}
+
+fn main() {
+    one_liners();
+    transmute_const();
+}
diff --git a/src/tools/clippy/tests/ui/transmuting_null.stderr b/src/tools/clippy/tests/ui/transmuting_null.stderr
new file mode 100644
index 00000000000..05f91ee2ada
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmuting_null.stderr
@@ -0,0 +1,22 @@
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:10:23
+   |
+LL |         let _: &u64 = std::mem::transmute(0 as *const u64);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::transmuting-null` implied by `-D warnings`
+
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:11:23
+   |
+LL |         let _: &u64 = std::mem::transmute(std::ptr::null::<u64>());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:21:23
+   |
+LL |         let _: &u64 = std::mem::transmute(ZPTR);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
new file mode 100644
index 00000000000..316426f1cf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
@@ -0,0 +1,114 @@
+// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)"
+// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
+
+#![deny(clippy::trivially_copy_pass_by_ref)]
+#![allow(
+    clippy::many_single_char_names,
+    clippy::blacklisted_name,
+    clippy::redundant_field_names
+)]
+
+#[derive(Copy, Clone)]
+struct Foo(u32);
+
+#[derive(Copy, Clone)]
+struct Bar([u8; 24]);
+
+#[derive(Copy, Clone)]
+pub struct Color {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+    pub a: u8,
+}
+
+struct FooRef<'a> {
+    foo: &'a Foo,
+}
+
+type Baz = u32;
+
+fn good(a: &mut u32, b: u32, c: &Bar) {}
+
+fn good_return_implicit_lt_ref(foo: &Foo) -> &u32 {
+    &foo.0
+}
+
+#[allow(clippy::needless_lifetimes)]
+fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
+    &foo.0
+}
+
+fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
+    FooRef { foo }
+}
+
+#[allow(clippy::needless_lifetimes)]
+fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> {
+    FooRef { foo }
+}
+
+fn bad(x: &u32, y: &Foo, z: &Baz) {}
+
+impl Foo {
+    fn good(self, a: &mut u32, b: u32, c: &Bar) {}
+
+    fn good2(&mut self) {}
+
+    fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
+
+    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+}
+
+impl AsRef<u32> for Foo {
+    fn as_ref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+impl Bar {
+    fn good(&self, a: &mut u32, b: u32, c: &Bar) {}
+
+    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+}
+
+trait MyTrait {
+    fn trait_method(&self, _foo: &Foo);
+}
+
+pub trait MyTrait2 {
+    fn trait_method2(&self, _color: &Color);
+}
+
+impl MyTrait for Foo {
+    fn trait_method(&self, _foo: &Foo) {
+        unimplemented!()
+    }
+}
+
+#[allow(unused_variables)]
+mod issue3992 {
+    pub trait A {
+        #[allow(clippy::trivially_copy_pass_by_ref)]
+        fn a(b: &u16) {}
+    }
+
+    #[allow(clippy::trivially_copy_pass_by_ref)]
+    pub fn c(d: &u16) {}
+}
+
+fn main() {
+    let (mut foo, bar) = (Foo(0), Bar([0; 24]));
+    let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0);
+    good(&mut a, b, &c);
+    good_return_implicit_lt_ref(&y);
+    good_return_explicit_lt_ref(&y);
+    bad(&x, &y, &z);
+    foo.good(&mut a, b, &c);
+    foo.good2();
+    foo.bad(&x, &y, &z);
+    Foo::bad2(&x, &y, &z);
+    bar.good(&mut a, b, &c);
+    Bar::bad2(&x, &y, &z);
+    foo.as_ref();
+}
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
new file mode 100644
index 00000000000..be0914e4a79
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -0,0 +1,98 @@
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:51:11
+   |
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
+   |           ^^^^ help: consider passing by value instead: `u32`
+   |
+note: the lint level is defined here
+  --> $DIR/trivially_copy_pass_by_ref.rs:4:9
+   |
+LL | #![deny(clippy::trivially_copy_pass_by_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:51:20
+   |
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
+   |                    ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:51:29
+   |
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
+   |                             ^^^^ help: consider passing by value instead: `Baz`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:58:12
+   |
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
+   |            ^^^^^ help: consider passing by value instead: `self`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:58:22
+   |
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
+   |                      ^^^^ help: consider passing by value instead: `u32`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:58:31
+   |
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
+   |                               ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:58:40
+   |
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
+   |                                        ^^^^ help: consider passing by value instead: `Baz`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:60:16
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                ^^^^ help: consider passing by value instead: `u32`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:60:25
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                         ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:60:34
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                                  ^^^^ help: consider passing by value instead: `Baz`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:72:16
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                ^^^^ help: consider passing by value instead: `u32`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:72:25
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                         ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:72:34
+   |
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+   |                                  ^^^^ help: consider passing by value instead: `Baz`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:76:34
+   |
+LL |     fn trait_method(&self, _foo: &Foo);
+   |                                  ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> $DIR/trivially_copy_pass_by_ref.rs:80:37
+   |
+LL |     fn trait_method2(&self, _color: &Color);
+   |                                     ^^^^^^ help: consider passing by value instead: `Color`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
new file mode 100644
index 00000000000..29d9139d3e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -0,0 +1,106 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
+#![deny(clippy::try_err)]
+
+#[macro_use]
+extern crate macro_rules;
+
+// Tests that a simple case works
+// Should flag `Err(err)?`
+pub fn basic_test() -> Result<i32, i32> {
+    let err: i32 = 1;
+    // To avoid warnings during rustfix
+    if true {
+        return Err(err);
+    }
+    Ok(0)
+}
+
+// Tests that `.into()` is added when appropriate
+pub fn into_test() -> Result<i32, i32> {
+    let err: u8 = 1;
+    // To avoid warnings during rustfix
+    if true {
+        return Err(err.into());
+    }
+    Ok(0)
+}
+
+// Tests that tries in general don't trigger the error
+pub fn negative_test() -> Result<i32, i32> {
+    Ok(nested_error()? + 1)
+}
+
+// Tests that `.into()` isn't added when the error type
+// matches the surrounding closure's return type, even
+// when it doesn't match the surrounding function's.
+pub fn closure_matches_test() -> Result<i32, i32> {
+    let res: Result<i32, i8> = Some(1)
+        .into_iter()
+        .map(|i| {
+            let err: i8 = 1;
+            // To avoid warnings during rustfix
+            if true {
+                return Err(err);
+            }
+            Ok(i)
+        })
+        .next()
+        .unwrap();
+
+    Ok(res?)
+}
+
+// Tests that `.into()` isn't added when the error type
+// doesn't match the surrounding closure's return type.
+pub fn closure_into_test() -> Result<i32, i32> {
+    let res: Result<i32, i16> = Some(1)
+        .into_iter()
+        .map(|i| {
+            let err: i8 = 1;
+            // To avoid warnings during rustfix
+            if true {
+                return Err(err.into());
+            }
+            Ok(i)
+        })
+        .next()
+        .unwrap();
+
+    Ok(res?)
+}
+
+fn nested_error() -> Result<i32, i32> {
+    Ok(1)
+}
+
+fn main() {
+    basic_test().unwrap();
+    into_test().unwrap();
+    negative_test().unwrap();
+    closure_matches_test().unwrap();
+    closure_into_test().unwrap();
+
+    // We don't want to lint in external macros
+    try_err!();
+}
+
+macro_rules! bar {
+    () => {
+        String::from("aasdfasdfasdfa")
+    };
+}
+
+macro_rules! foo {
+    () => {
+        bar!()
+    };
+}
+
+pub fn macro_inside(fail: bool) -> Result<i32, String> {
+    if fail {
+        return Err(foo!());
+    }
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
new file mode 100644
index 00000000000..5e85d091a2a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -0,0 +1,106 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
+#![deny(clippy::try_err)]
+
+#[macro_use]
+extern crate macro_rules;
+
+// Tests that a simple case works
+// Should flag `Err(err)?`
+pub fn basic_test() -> Result<i32, i32> {
+    let err: i32 = 1;
+    // To avoid warnings during rustfix
+    if true {
+        Err(err)?;
+    }
+    Ok(0)
+}
+
+// Tests that `.into()` is added when appropriate
+pub fn into_test() -> Result<i32, i32> {
+    let err: u8 = 1;
+    // To avoid warnings during rustfix
+    if true {
+        Err(err)?;
+    }
+    Ok(0)
+}
+
+// Tests that tries in general don't trigger the error
+pub fn negative_test() -> Result<i32, i32> {
+    Ok(nested_error()? + 1)
+}
+
+// Tests that `.into()` isn't added when the error type
+// matches the surrounding closure's return type, even
+// when it doesn't match the surrounding function's.
+pub fn closure_matches_test() -> Result<i32, i32> {
+    let res: Result<i32, i8> = Some(1)
+        .into_iter()
+        .map(|i| {
+            let err: i8 = 1;
+            // To avoid warnings during rustfix
+            if true {
+                Err(err)?;
+            }
+            Ok(i)
+        })
+        .next()
+        .unwrap();
+
+    Ok(res?)
+}
+
+// Tests that `.into()` isn't added when the error type
+// doesn't match the surrounding closure's return type.
+pub fn closure_into_test() -> Result<i32, i32> {
+    let res: Result<i32, i16> = Some(1)
+        .into_iter()
+        .map(|i| {
+            let err: i8 = 1;
+            // To avoid warnings during rustfix
+            if true {
+                Err(err)?;
+            }
+            Ok(i)
+        })
+        .next()
+        .unwrap();
+
+    Ok(res?)
+}
+
+fn nested_error() -> Result<i32, i32> {
+    Ok(1)
+}
+
+fn main() {
+    basic_test().unwrap();
+    into_test().unwrap();
+    negative_test().unwrap();
+    closure_matches_test().unwrap();
+    closure_into_test().unwrap();
+
+    // We don't want to lint in external macros
+    try_err!();
+}
+
+macro_rules! bar {
+    () => {
+        String::from("aasdfasdfasdfa")
+    };
+}
+
+macro_rules! foo {
+    () => {
+        bar!()
+    };
+}
+
+pub fn macro_inside(fail: bool) -> Result<i32, String> {
+    if fail {
+        Err(foo!())?;
+    }
+    Ok(0)
+}
diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr
new file mode 100644
index 00000000000..21e9d4048a5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/try_err.stderr
@@ -0,0 +1,38 @@
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:15:9
+   |
+LL |         Err(err)?;
+   |         ^^^^^^^^^ help: try this: `return Err(err)`
+   |
+note: the lint level is defined here
+  --> $DIR/try_err.rs:4:9
+   |
+LL | #![deny(clippy::try_err)]
+   |         ^^^^^^^^^^^^^^^
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:25:9
+   |
+LL |         Err(err)?;
+   |         ^^^^^^^^^ help: try this: `return Err(err.into())`
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:45:17
+   |
+LL |                 Err(err)?;
+   |                 ^^^^^^^^^ help: try this: `return Err(err)`
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:64:17
+   |
+LL |                 Err(err)?;
+   |                 ^^^^^^^^^ help: try this: `return Err(err.into())`
+
+error: returning an `Err(_)` with the `?` operator
+  --> $DIR/try_err.rs:103:9
+   |
+LL |         Err(foo!())?;
+   |         ^^^^^^^^^^^^ help: try this: `return Err(foo!())`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ty_fn_sig.rs b/src/tools/clippy/tests/ui/ty_fn_sig.rs
new file mode 100644
index 00000000000..9e2753dcb18
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ty_fn_sig.rs
@@ -0,0 +1,14 @@
+// Regression test
+
+pub fn retry<F: Fn()>(f: F) {
+    for _i in 0.. {
+        f();
+    }
+}
+
+fn main() {
+    for y in 0..4 {
+        let func = || ();
+        func();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
new file mode 100644
index 00000000000..8b538be762b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
@@ -0,0 +1,19 @@
+#[deny(clippy::type_repetition_in_bounds)]
+
+pub fn foo<T>(_t: T)
+where
+    T: Copy,
+    T: Clone,
+{
+    unimplemented!();
+}
+
+pub fn bar<T, U>(_t: T, _u: U)
+where
+    T: Copy,
+    U: Clone,
+{
+    unimplemented!();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
new file mode 100644
index 00000000000..4264e2e10bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
@@ -0,0 +1,15 @@
+error: this type has already been used as a bound predicate
+  --> $DIR/type_repetition_in_bounds.rs:6:5
+   |
+LL |     T: Clone,
+   |     ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/type_repetition_in_bounds.rs:1:8
+   |
+LL | #[deny(clippy::type_repetition_in_bounds)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider combining the bounds: `T: Copy + Clone`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/types.fixed b/src/tools/clippy/tests/ui/types.fixed
new file mode 100644
index 00000000000..417da42edf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/types.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::cast_lossless)]
+
+// should not warn on lossy casting in constant types
+// because not supported yet
+const C: i32 = 42;
+const C_I64: i64 = C as i64;
+
+fn main() {
+    // should suggest i64::from(c)
+    let c: i32 = 42;
+    let c_i64: i64 = i64::from(c);
+}
diff --git a/src/tools/clippy/tests/ui/types.rs b/src/tools/clippy/tests/ui/types.rs
new file mode 100644
index 00000000000..b16e9e538b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/types.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::cast_lossless)]
+
+// should not warn on lossy casting in constant types
+// because not supported yet
+const C: i32 = 42;
+const C_I64: i64 = C as i64;
+
+fn main() {
+    // should suggest i64::from(c)
+    let c: i32 = 42;
+    let c_i64: i64 = c as i64;
+}
diff --git a/src/tools/clippy/tests/ui/types.stderr b/src/tools/clippy/tests/ui/types.stderr
new file mode 100644
index 00000000000..59c3e05a1aa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/types.stderr
@@ -0,0 +1,10 @@
+error: casting `i32` to `i64` may become silently lossy if you later change the type
+  --> $DIR/types.rs:14:22
+   |
+LL |     let c_i64: i64 = c as i64;
+   |                      ^^^^^^^^ help: try: `i64::from(c)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs
new file mode 100644
index 00000000000..27db9594f3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unicode.rs
@@ -0,0 +1,23 @@
+#[warn(clippy::zero_width_space)]
+fn zero() {
+    print!("Here >​< is a ZWS, and ​another");
+    print!("This\u{200B}is\u{200B}fine");
+}
+
+#[warn(clippy::unicode_not_nfc)]
+fn canon() {
+    print!("̀àh?");
+    print!("a\u{0300}h?"); // also ok
+}
+
+#[warn(clippy::non_ascii_literal)]
+fn uni() {
+    print!("Üben!");
+    print!("\u{DC}ben!"); // this is ok
+}
+
+fn main() {
+    zero();
+    uni();
+    canon();
+}
diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr
new file mode 100644
index 00000000000..4575a132e5b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unicode.stderr
@@ -0,0 +1,26 @@
+error: zero-width space detected
+  --> $DIR/unicode.rs:3:12
+   |
+LL |     print!("Here >​< is a ZWS, and ​another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
+   |
+   = note: `-D clippy::zero-width-space` implied by `-D warnings`
+
+error: non-NFC Unicode sequence detected
+  --> $DIR/unicode.rs:9:12
+   |
+LL |     print!("̀àh?");
+   |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
+   |
+   = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
+
+error: literal non-ASCII character detected
+  --> $DIR/unicode.rs:15:12
+   |
+LL |     print!("Üben!");
+   |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
+   |
+   = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs
new file mode 100644
index 00000000000..f42b884e0f0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninit.rs
@@ -0,0 +1,22 @@
+#![feature(stmt_expr_attributes)]
+
+use std::mem::MaybeUninit;
+
+fn main() {
+    let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // edge case: For now we lint on empty arrays
+    let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // edge case: For now we accept unit tuples
+    let _: () = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // This is OK, because `MaybeUninit` allows uninitialized data.
+    let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // This is OK, because all constitutent types are uninit-compatible.
+    let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // This is OK, because all constitutent types are uninit-compatible.
+    let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
+}
diff --git a/src/tools/clippy/tests/ui/uninit.stderr b/src/tools/clippy/tests/ui/uninit.stderr
new file mode 100644
index 00000000000..a37233ecdda
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninit.stderr
@@ -0,0 +1,16 @@
+error: this call for this type may be undefined behavior
+  --> $DIR/uninit.rs:6:29
+   |
+LL |     let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::uninit_assumed_init)]` on by default
+
+error: this call for this type may be undefined behavior
+  --> $DIR/uninit.rs:9:31
+   |
+LL |     let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unit_arg.fixed b/src/tools/clippy/tests/ui/unit_arg.fixed
new file mode 100644
index 00000000000..a739cf7ad81
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg.fixed
@@ -0,0 +1,64 @@
+// 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
new file mode 100644
index 00000000000..d90c49f79de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -0,0 +1,71 @@
+// 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({
+        1;
+    });
+    foo(foo(1));
+    foo({
+        foo(1);
+        foo(2);
+    });
+    foo3({}, 2, 2);
+    let b = Bar;
+    b.bar({
+        1;
+    });
+}
+
+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.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
new file mode 100644
index 00000000000..21ccc684ea9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -0,0 +1,79 @@
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:24:9
+   |
+LL |     foo({});
+   |         ^^
+   |
+   = note: `-D clippy::unit-arg` implied by `-D warnings`
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     foo(());
+   |         ^^
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:25:9
+   |
+LL |       foo({
+   |  _________^
+LL | |         1;
+LL | |     });
+   | |_____^
+   |
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     foo(());
+   |         ^^
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:28:9
+   |
+LL |     foo(foo(1));
+   |         ^^^^^^
+   |
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     foo(());
+   |         ^^
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:29:9
+   |
+LL |       foo({
+   |  _________^
+LL | |         foo(1);
+LL | |         foo(2);
+LL | |     });
+   | |_____^
+   |
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     foo(());
+   |         ^^
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:33:10
+   |
+LL |     foo3({}, 2, 2);
+   |          ^^
+   |
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     foo3((), 2, 2);
+   |          ^^
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:35:11
+   |
+LL |       b.bar({
+   |  ___________^
+LL | |         1;
+LL | |     });
+   | |_____^
+   |
+help: if you intended to pass a unit value, use a unit literal instead
+   |
+LL |     b.bar(());
+   |           ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unit_cmp.rs b/src/tools/clippy/tests/ui/unit_cmp.rs
new file mode 100644
index 00000000000..8d3a4eed82e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_cmp.rs
@@ -0,0 +1,57 @@
+#![warn(clippy::unit_cmp)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+#[derive(PartialEq)]
+pub struct ContainsUnit(()); // should be fine
+
+fn main() {
+    // this is fine
+    if true == false {}
+
+    // this warns
+    if {
+        true;
+    } == {
+        false;
+    } {}
+
+    if {
+        true;
+    } > {
+        false;
+    } {}
+
+    assert_eq!(
+        {
+            true;
+        },
+        {
+            false;
+        }
+    );
+    debug_assert_eq!(
+        {
+            true;
+        },
+        {
+            false;
+        }
+    );
+
+    assert_ne!(
+        {
+            true;
+        },
+        {
+            false;
+        }
+    );
+    debug_assert_ne!(
+        {
+            true;
+        },
+        {
+            false;
+        }
+    );
+}
diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr
new file mode 100644
index 00000000000..c8c0a85dfc1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_cmp.stderr
@@ -0,0 +1,82 @@
+error: ==-comparison of unit values detected. This will always be true
+  --> $DIR/unit_cmp.rs:12:8
+   |
+LL |       if {
+   |  ________^
+LL | |         true;
+LL | |     } == {
+LL | |         false;
+LL | |     } {}
+   | |_____^
+   |
+   = note: `-D clippy::unit-cmp` implied by `-D warnings`
+
+error: >-comparison of unit values detected. This will always be false
+  --> $DIR/unit_cmp.rs:18:8
+   |
+LL |       if {
+   |  ________^
+LL | |         true;
+LL | |     } > {
+LL | |         false;
+LL | |     } {}
+   | |_____^
+
+error: `assert_eq` of unit values detected. This will always succeed
+  --> $DIR/unit_cmp.rs:24:5
+   |
+LL | /     assert_eq!(
+LL | |         {
+LL | |             true;
+LL | |         },
+...  |
+LL | |         }
+LL | |     );
+   | |______^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `debug_assert_eq` of unit values detected. This will always succeed
+  --> $DIR/unit_cmp.rs:32:5
+   |
+LL | /     debug_assert_eq!(
+LL | |         {
+LL | |             true;
+LL | |         },
+...  |
+LL | |         }
+LL | |     );
+   | |______^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `assert_ne` of unit values detected. This will always fail
+  --> $DIR/unit_cmp.rs:41:5
+   |
+LL | /     assert_ne!(
+LL | |         {
+LL | |             true;
+LL | |         },
+...  |
+LL | |         }
+LL | |     );
+   | |______^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `debug_assert_ne` of unit values detected. This will always fail
+  --> $DIR/unit_cmp.rs:49:5
+   |
+LL | /     debug_assert_ne!(
+LL | |         {
+LL | |             true;
+LL | |         },
+...  |
+LL | |         }
+LL | |     );
+   | |______^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unknown_attribute.rs b/src/tools/clippy/tests/ui/unknown_attribute.rs
new file mode 100644
index 00000000000..e993e63f8ed
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unknown_attribute.rs
@@ -0,0 +1,3 @@
+#[clippy::unknown]
+#[clippy::cognitive_complexity = "1"]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unknown_attribute.stderr b/src/tools/clippy/tests/ui/unknown_attribute.stderr
new file mode 100644
index 00000000000..47e37aed246
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unknown_attribute.stderr
@@ -0,0 +1,8 @@
+error: Usage of unknown attribute
+  --> $DIR/unknown_attribute.rs:1:11
+   |
+LL | #[clippy::unknown]
+   |           ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed
new file mode 100644
index 00000000000..4249ff8a958
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::pedantic)]
+// Should suggest lowercase
+#![allow(clippy::all)]
+#![warn(clippy::cmp_nan)]
+
+// Should suggest similar clippy lint name
+#[warn(clippy::if_not_else)]
+#[warn(clippy::unnecessary_cast)]
+#[warn(clippy::useless_transmute)]
+// Shouldn't suggest rustc lint name(`dead_code`)
+#[warn(clippy::drop_copy)]
+// Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`)
+#[warn(clippy::unused_self)]
+// Shouldn't suggest renamed clippy lint name(`const_static_lifetime`)
+#[warn(clippy::redundant_static_lifetimes)]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs
new file mode 100644
index 00000000000..5db345f5444
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::pedantic)]
+// Should suggest lowercase
+#![allow(clippy::All)]
+#![warn(clippy::CMP_NAN)]
+
+// Should suggest similar clippy lint name
+#[warn(clippy::if_not_els)]
+#[warn(clippy::UNNecsaRy_cAst)]
+#[warn(clippy::useles_transute)]
+// Shouldn't suggest rustc lint name(`dead_code`)
+#[warn(clippy::dead_cod)]
+// Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`)
+#[warn(clippy::unused_colle)]
+// Shouldn't suggest renamed clippy lint name(`const_static_lifetime`)
+#[warn(clippy::const_static_lifetim)]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
new file mode 100644
index 00000000000..1b859043bb5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr
@@ -0,0 +1,52 @@
+error: unknown clippy lint: clippy::if_not_els
+  --> $DIR/unknown_clippy_lints.rs:9:8
+   |
+LL | #[warn(clippy::if_not_els)]
+   |        ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else`
+   |
+   = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings`
+
+error: unknown clippy lint: clippy::UNNecsaRy_cAst
+  --> $DIR/unknown_clippy_lints.rs:10:8
+   |
+LL | #[warn(clippy::UNNecsaRy_cAst)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unnecessary_cast`
+
+error: unknown clippy lint: clippy::useles_transute
+  --> $DIR/unknown_clippy_lints.rs:11:8
+   |
+LL | #[warn(clippy::useles_transute)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::useless_transmute`
+
+error: unknown clippy lint: clippy::dead_cod
+  --> $DIR/unknown_clippy_lints.rs:13:8
+   |
+LL | #[warn(clippy::dead_cod)]
+   |        ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy`
+
+error: unknown clippy lint: clippy::unused_colle
+  --> $DIR/unknown_clippy_lints.rs:15:8
+   |
+LL | #[warn(clippy::unused_colle)]
+   |        ^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unused_self`
+
+error: unknown clippy lint: clippy::const_static_lifetim
+  --> $DIR/unknown_clippy_lints.rs:17:8
+   |
+LL | #[warn(clippy::const_static_lifetim)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes`
+
+error: unknown clippy lint: clippy::All
+  --> $DIR/unknown_clippy_lints.rs:5:10
+   |
+LL | #![allow(clippy::All)]
+   |          ^^^^^^^^^^^ help: lowercase the lint name: `clippy::all`
+
+error: unknown clippy lint: clippy::CMP_NAN
+  --> $DIR/unknown_clippy_lints.rs:6:9
+   |
+LL | #![warn(clippy::CMP_NAN)]
+   |         ^^^^^^^^^^^^^^^ help: lowercase the lint name: `clippy::cmp_nan`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
new file mode 100644
index 00000000000..df9b227eeb3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -0,0 +1,23 @@
+#![warn(clippy::unnecessary_cast)]
+#![allow(clippy::no_effect)]
+
+fn main() {
+    // Test cast_unnecessary
+    1i32 as i32;
+    1f32 as f32;
+    false as bool;
+    &1i32 as &i32;
+
+    // macro version
+    macro_rules! foo {
+        ($a:ident, $b:ident) => {
+            #[allow(unused)]
+            pub fn $a() -> $b {
+                1 as $b
+            }
+        };
+    }
+    foo!(a, i32);
+    foo!(b, f32);
+    foo!(c, f64);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
new file mode 100644
index 00000000000..8981d13e8ea
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -0,0 +1,22 @@
+error: casting to the same type is unnecessary (`i32` -> `i32`)
+  --> $DIR/unnecessary_cast.rs:6:5
+   |
+LL |     1i32 as i32;
+   |     ^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+
+error: casting to the same type is unnecessary (`f32` -> `f32`)
+  --> $DIR/unnecessary_cast.rs:7:5
+   |
+LL |     1f32 as f32;
+   |     ^^^^^^^^^^^
+
+error: casting to the same type is unnecessary (`bool` -> `bool`)
+  --> $DIR/unnecessary_cast.rs:8:5
+   |
+LL |     false as bool;
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed
new file mode 100644
index 00000000000..fb89a9fce3d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![warn(clippy::unnecessary_cast)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+fn main() {
+    // casting integer literal to float is unnecessary
+    100_f32;
+    100_f64;
+    100_f64;
+    // Should not trigger
+    #[rustfmt::skip]
+    let v = vec!(1);
+    &v as &[i32];
+    1.0 as f64;
+    1 as u64;
+    0x10 as f32;
+    0o10 as f32;
+    0b10 as f32;
+    0x11 as f64;
+    0o11 as f64;
+    0b11 as f64;
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs
new file mode 100644
index 00000000000..4a0c8620dc1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![warn(clippy::unnecessary_cast)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+
+fn main() {
+    // casting integer literal to float is unnecessary
+    100 as f32;
+    100 as f64;
+    100_i32 as f64;
+    // Should not trigger
+    #[rustfmt::skip]
+    let v = vec!(1);
+    &v as &[i32];
+    1.0 as f64;
+    1 as u64;
+    0x10 as f32;
+    0o10 as f32;
+    0b10 as f32;
+    0x11 as f64;
+    0o11 as f64;
+    0b11 as f64;
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_fixable.stderr b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.stderr
new file mode 100644
index 00000000000..8ff1e5dea60
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_fixable.stderr
@@ -0,0 +1,22 @@
+error: casting integer literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast_fixable.rs:8:5
+   |
+LL |     100 as f32;
+   |     ^^^^^^^^^^ help: try: `100_f32`
+   |
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast_fixable.rs:9:5
+   |
+LL |     100 as f64;
+   |     ^^^^^^^^^^ help: try: `100_f64`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast_fixable.rs:10:5
+   |
+LL |     100_i32 as f64;
+   |     ^^^^^^^^^^^^^^ help: try: `100_f64`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs
new file mode 100644
index 00000000000..f1cc5b564c1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs
@@ -0,0 +1,117 @@
+// does not test any rustfixable lints
+
+#![warn(clippy::clone_on_ref_ptr)]
+#![allow(unused, clippy::redundant_clone)]
+
+use std::cell::RefCell;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+trait SomeTrait {}
+struct SomeImpl;
+impl SomeTrait for SomeImpl {}
+
+fn main() {}
+
+fn is_ascii(ch: char) -> bool {
+    ch.is_ascii()
+}
+
+fn clone_on_copy() {
+    42.clone();
+
+    vec![1].clone(); // ok, not a Copy type
+    Some(vec![1]).clone(); // ok, not a Copy type
+    (&42).clone();
+
+    let rc = RefCell::new(0);
+    rc.borrow().clone();
+
+    // Issue #4348
+    let mut x = 43;
+    let _ = &x.clone(); // ok, getting a ref
+    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
+    is_ascii('z'.clone());
+
+    // Issue #5436
+    let mut vec = Vec::new();
+    vec.push(42.clone());
+}
+
+fn clone_on_ref_ptr() {
+    let rc = Rc::new(true);
+    let arc = Arc::new(true);
+
+    let rcweak = Rc::downgrade(&rc);
+    let arc_weak = Arc::downgrade(&arc);
+
+    rc.clone();
+    Rc::clone(&rc);
+
+    arc.clone();
+    Arc::clone(&arc);
+
+    rcweak.clone();
+    rc::Weak::clone(&rcweak);
+
+    arc_weak.clone();
+    sync::Weak::clone(&arc_weak);
+
+    let x = Arc::new(SomeImpl);
+    let _: Arc<dyn SomeTrait> = x.clone();
+}
+
+fn clone_on_copy_generic<T: Copy>(t: T) {
+    t.clone();
+
+    Some(t).clone();
+}
+
+fn clone_on_double_ref() {
+    let x = vec![1];
+    let y = &&x;
+    let z: &Vec<_> = y.clone();
+
+    println!("{:p} {:p}", *y, z);
+}
+
+mod many_derefs {
+    struct A;
+    struct B;
+    struct C;
+    struct D;
+    #[derive(Copy, Clone)]
+    struct E;
+
+    macro_rules! impl_deref {
+        ($src:ident, $dst:ident) => {
+            impl std::ops::Deref for $src {
+                type Target = $dst;
+                fn deref(&self) -> &Self::Target {
+                    &$dst
+                }
+            }
+        };
+    }
+
+    impl_deref!(A, B);
+    impl_deref!(B, C);
+    impl_deref!(C, D);
+    impl std::ops::Deref for D {
+        type Target = &'static E;
+        fn deref(&self) -> &Self::Target {
+            &&E
+        }
+    }
+
+    fn go1() {
+        let a = A;
+        let _: E = a.clone();
+        let _: E = *****a;
+    }
+
+    fn check(mut encoded: &[u8]) {
+        let _ = &mut encoded.clone();
+        let _ = &encoded.clone();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
new file mode 100644
index 00000000000..6176a2bc464
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
@@ -0,0 +1,130 @@
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:21:5
+   |
+LL |     42.clone();
+   |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
+   |
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:25:5
+   |
+LL |     (&42).clone();
+   |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:28:5
+   |
+LL |     rc.borrow().clone();
+   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:34:14
+   |
+LL |     is_ascii('z'.clone());
+   |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:38:14
+   |
+LL |     vec.push(42.clone());
+   |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
+
+error: using `.clone()` on a ref-counted pointer
+  --> $DIR/unnecessary_clone.rs:48:5
+   |
+LL |     rc.clone();
+   |     ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
+   |
+   = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
+
+error: using `.clone()` on a ref-counted pointer
+  --> $DIR/unnecessary_clone.rs:51:5
+   |
+LL |     arc.clone();
+   |     ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
+
+error: using `.clone()` on a ref-counted pointer
+  --> $DIR/unnecessary_clone.rs:54:5
+   |
+LL |     rcweak.clone();
+   |     ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
+
+error: using `.clone()` on a ref-counted pointer
+  --> $DIR/unnecessary_clone.rs:57:5
+   |
+LL |     arc_weak.clone();
+   |     ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
+
+error: using `.clone()` on a ref-counted pointer
+  --> $DIR/unnecessary_clone.rs:61:33
+   |
+LL |     let _: Arc<dyn SomeTrait> = x.clone();
+   |                                 ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:65:5
+   |
+LL |     t.clone();
+   |     ^^^^^^^^^ help: try removing the `clone` call: `t`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:67:5
+   |
+LL |     Some(t).clone();
+   |     ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
+
+error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
+  --> $DIR/unnecessary_clone.rs:73:22
+   |
+LL |     let z: &Vec<_> = y.clone();
+   |                      ^^^^^^^^^
+   |
+   = note: `#[deny(clippy::clone_double_ref)]` on by default
+help: try dereferencing it
+   |
+LL |     let z: &Vec<_> = &(*y).clone();
+   |                      ^^^^^^^^^^^^^
+help: or try being explicit if you are sure, that you want to clone a reference
+   |
+LL |     let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:109:20
+   |
+LL |         let _: E = a.clone();
+   |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
+
+error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
+  --> $DIR/unnecessary_clone.rs:114:22
+   |
+LL |         let _ = &mut encoded.clone();
+   |                      ^^^^^^^^^^^^^^^
+   |
+help: try dereferencing it
+   |
+LL |         let _ = &mut &(*encoded).clone();
+   |                      ^^^^^^^^^^^^^^^^^^^
+help: or try being explicit if you are sure, that you want to clone a reference
+   |
+LL |         let _ = &mut <&[u8]>::clone(encoded);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
+  --> $DIR/unnecessary_clone.rs:115:18
+   |
+LL |         let _ = &encoded.clone();
+   |                  ^^^^^^^^^^^^^^^
+   |
+help: try dereferencing it
+   |
+LL |         let _ = &&(*encoded).clone();
+   |                  ^^^^^^^^^^^^^^^^^^^
+help: or try being explicit if you are sure, that you want to clone a reference
+   |
+LL |         let _ = &<&[u8]>::clone(encoded);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
new file mode 100644
index 00000000000..af858e4abcf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
@@ -0,0 +1,17 @@
+fn main() {
+    let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
+    let _ = (0..4).filter_map(|x| {
+        if x > 1 {
+            return Some(x);
+        };
+        None
+    });
+    let _ = (0..4).filter_map(|x| match x {
+        0 | 1 => None,
+        _ => Some(x),
+    });
+
+    let _ = (0..4).filter_map(|x| Some(x + 1));
+
+    let _ = (0..4).filter_map(i32::checked_abs);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
new file mode 100644
index 00000000000..041829c3c78
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
@@ -0,0 +1,38 @@
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:2:13
+   |
+LL |     let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings`
+
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:3:13
+   |
+LL |       let _ = (0..4).filter_map(|x| {
+   |  _____________^
+LL | |         if x > 1 {
+LL | |             return Some(x);
+LL | |         };
+LL | |         None
+LL | |     });
+   | |______^
+
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:9:13
+   |
+LL |       let _ = (0..4).filter_map(|x| match x {
+   |  _____________^
+LL | |         0 | 1 => None,
+LL | |         _ => Some(x),
+LL | |     });
+   | |______^
+
+error: this `.filter_map` can be written more simply using `.map`
+  --> $DIR/unnecessary_filter_map.rs:14:13
+   |
+LL |     let _ = (0..4).filter_map(|x| Some(x + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.fixed b/src/tools/clippy/tests/ui/unnecessary_flat_map.fixed
new file mode 100644
index 00000000000..dfe3bd47e13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_flat_map.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(unused_imports)]
+#![warn(clippy::flat_map_identity)]
+
+use std::convert;
+
+fn main() {
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flatten();
+
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flatten();
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.rs b/src/tools/clippy/tests/ui/unnecessary_flat_map.rs
new file mode 100644
index 00000000000..393b9569255
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_flat_map.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(unused_imports)]
+#![warn(clippy::flat_map_identity)]
+
+use std::convert;
+
+fn main() {
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flat_map(|x| x);
+
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flat_map(convert::identity);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.stderr b/src/tools/clippy/tests/ui/unnecessary_flat_map.stderr
new file mode 100644
index 00000000000..a1cd5745e49
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_flat_map.stderr
@@ -0,0 +1,16 @@
+error: called `flat_map(|x| x)` on an `Iterator`
+  --> $DIR/unnecessary_flat_map.rs:10:22
+   |
+LL |     let _ = iterator.flat_map(|x| x);
+   |                      ^^^^^^^^^^^^^^^ help: try: `flatten()`
+   |
+   = note: `-D clippy::flat-map-identity` implied by `-D warnings`
+
+error: called `flat_map(std::convert::identity)` on an `Iterator`
+  --> $DIR/unnecessary_flat_map.rs:13:22
+   |
+LL |     let _ = iterator.flat_map(convert::identity);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.fixed b/src/tools/clippy/tests/ui/unnecessary_fold.fixed
new file mode 100644
index 00000000000..52300a3b640
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.fixed
@@ -0,0 +1,52 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+/// Calls which should trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold() {
+    // Can be replaced by .any
+    let _ = (0..3).any(|x| x > 2);
+    // Can be replaced by .all
+    let _ = (0..3).all(|x| x > 2);
+    // Can be replaced by .sum
+    let _: i32 = (0..3).sum();
+    // Can be replaced by .product
+    let _: i32 = (0..3).product();
+}
+
+/// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)`
+fn unnecessary_fold_span_for_multi_element_chain() {
+    let _: bool = (0..3).map(|x| 2 * x).any(|x| x > 2);
+}
+
+/// Calls which should not trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold_should_ignore() {
+    let _ = (0..3).fold(true, |acc, x| acc || x > 2);
+    let _ = (0..3).fold(false, |acc, x| acc && x > 2);
+    let _ = (0..3).fold(1, |acc, x| acc + x);
+    let _ = (0..3).fold(0, |acc, x| acc * x);
+    let _ = (0..3).fold(0, |acc, x| 1 + acc + x);
+
+    // We only match against an accumulator on the left
+    // hand side. We could lint for .sum and .product when
+    // it's on the right, but don't for now (and this wouldn't
+    // be valid if we extended the lint to cover arbitrary numeric
+    // types).
+    let _ = (0..3).fold(false, |acc, x| x > 2 || acc);
+    let _ = (0..3).fold(true, |acc, x| x > 2 && acc);
+    let _ = (0..3).fold(0, |acc, x| x + acc);
+    let _ = (0..3).fold(1, |acc, x| x * acc);
+
+    let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len());
+    let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len());
+}
+
+/// Should lint only the line containing the fold
+fn unnecessary_fold_over_multiple_lines() {
+    let _ = (0..3)
+        .map(|x| x + 1)
+        .filter(|x| x % 2 == 0)
+        .any(|x| x > 2);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.rs b/src/tools/clippy/tests/ui/unnecessary_fold.rs
new file mode 100644
index 00000000000..4028d80c0a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.rs
@@ -0,0 +1,52 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+/// Calls which should trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold() {
+    // Can be replaced by .any
+    let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+    // Can be replaced by .all
+    let _ = (0..3).fold(true, |acc, x| acc && x > 2);
+    // Can be replaced by .sum
+    let _: i32 = (0..3).fold(0, |acc, x| acc + x);
+    // Can be replaced by .product
+    let _: i32 = (0..3).fold(1, |acc, x| acc * x);
+}
+
+/// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)`
+fn unnecessary_fold_span_for_multi_element_chain() {
+    let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
+}
+
+/// Calls which should not trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold_should_ignore() {
+    let _ = (0..3).fold(true, |acc, x| acc || x > 2);
+    let _ = (0..3).fold(false, |acc, x| acc && x > 2);
+    let _ = (0..3).fold(1, |acc, x| acc + x);
+    let _ = (0..3).fold(0, |acc, x| acc * x);
+    let _ = (0..3).fold(0, |acc, x| 1 + acc + x);
+
+    // We only match against an accumulator on the left
+    // hand side. We could lint for .sum and .product when
+    // it's on the right, but don't for now (and this wouldn't
+    // be valid if we extended the lint to cover arbitrary numeric
+    // types).
+    let _ = (0..3).fold(false, |acc, x| x > 2 || acc);
+    let _ = (0..3).fold(true, |acc, x| x > 2 && acc);
+    let _ = (0..3).fold(0, |acc, x| x + acc);
+    let _ = (0..3).fold(1, |acc, x| x * acc);
+
+    let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len());
+    let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len());
+}
+
+/// Should lint only the line containing the fold
+fn unnecessary_fold_over_multiple_lines() {
+    let _ = (0..3)
+        .map(|x| x + 1)
+        .filter(|x| x % 2 == 0)
+        .fold(false, |acc, x| acc || x > 2);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.stderr b/src/tools/clippy/tests/ui/unnecessary_fold.stderr
new file mode 100644
index 00000000000..22c44588ab7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fold.stderr
@@ -0,0 +1,40 @@
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:8:20
+   |
+LL |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
+   |
+   = note: `-D clippy::unnecessary-fold` implied by `-D warnings`
+
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:10:20
+   |
+LL |     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)`
+
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:12:25
+   |
+LL |     let _: i32 = (0..3).fold(0, |acc, x| acc + x);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()`
+
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:14:25
+   |
+LL |     let _: i32 = (0..3).fold(1, |acc, x| acc * x);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()`
+
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:19:41
+   |
+LL |     let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
+
+error: this `.fold` can be written more succinctly using another method
+  --> $DIR/unnecessary_fold.rs:49:10
+   |
+LL |         .fold(false, |acc, x| acc || x > 2);
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
new file mode 100644
index 00000000000..2fca96c4cd5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -0,0 +1,79 @@
+// run-rustfix
+
+#![feature(box_syntax)]
+#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)]
+#![warn(clippy::unnecessary_operation)]
+
+struct Tuple(i32);
+struct Struct {
+    field: i32,
+}
+enum Enum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+struct DropStruct {
+    field: i32,
+}
+impl Drop for DropStruct {
+    fn drop(&mut self) {}
+}
+struct DropTuple(i32);
+impl Drop for DropTuple {
+    fn drop(&mut self) {}
+}
+enum DropEnum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+impl Drop for DropEnum {
+    fn drop(&mut self) {}
+}
+struct FooString {
+    s: String,
+}
+
+fn get_number() -> i32 {
+    0
+}
+
+fn get_usize() -> usize {
+    0
+}
+fn get_struct() -> Struct {
+    Struct { field: 0 }
+}
+fn get_drop_struct() -> DropStruct {
+    DropStruct { field: 0 }
+}
+
+fn main() {
+    get_number();
+    get_number();
+    get_struct();
+    get_number();
+    get_number();
+    5;get_number();
+    get_number();
+    get_number();
+    5;6;get_number();
+    get_number();
+    get_number();
+    get_number();
+    5;get_number();
+    42;get_number();
+    [42, 55];get_usize();
+    42;get_number();
+    get_number();
+    [42; 55];get_usize();
+    get_number();
+    String::from("blah");
+
+    // Do not warn
+    DropTuple(get_number());
+    DropStruct { field: get_number() };
+    DropStruct { field: get_number() };
+    DropStruct { ..get_drop_struct() };
+    DropEnum::Tuple(get_number());
+    DropEnum::Struct { field: get_number() };
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs
new file mode 100644
index 00000000000..08cb9ab522e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs
@@ -0,0 +1,83 @@
+// run-rustfix
+
+#![feature(box_syntax)]
+#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)]
+#![warn(clippy::unnecessary_operation)]
+
+struct Tuple(i32);
+struct Struct {
+    field: i32,
+}
+enum Enum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+struct DropStruct {
+    field: i32,
+}
+impl Drop for DropStruct {
+    fn drop(&mut self) {}
+}
+struct DropTuple(i32);
+impl Drop for DropTuple {
+    fn drop(&mut self) {}
+}
+enum DropEnum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+impl Drop for DropEnum {
+    fn drop(&mut self) {}
+}
+struct FooString {
+    s: String,
+}
+
+fn get_number() -> i32 {
+    0
+}
+
+fn get_usize() -> usize {
+    0
+}
+fn get_struct() -> Struct {
+    Struct { field: 0 }
+}
+fn get_drop_struct() -> DropStruct {
+    DropStruct { field: 0 }
+}
+
+fn main() {
+    Tuple(get_number());
+    Struct { field: get_number() };
+    Struct { ..get_struct() };
+    Enum::Tuple(get_number());
+    Enum::Struct { field: get_number() };
+    5 + get_number();
+    *&get_number();
+    &get_number();
+    (5, 6, get_number());
+    box get_number();
+    get_number()..;
+    ..get_number();
+    5..get_number();
+    [42, get_number()];
+    [42, 55][get_usize()];
+    (42, get_number()).1;
+    [get_number(); 55];
+    [42; 55][get_usize()];
+    {
+        get_number()
+    };
+    FooString {
+        s: String::from("blah"),
+    };
+
+    // Do not warn
+    DropTuple(get_number());
+    DropStruct { field: get_number() };
+    DropStruct { field: get_number() };
+    DropStruct { ..get_drop_struct() };
+    DropEnum::Tuple(get_number());
+    DropEnum::Struct { field: get_number() };
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
new file mode 100644
index 00000000000..f88c9f9908b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
@@ -0,0 +1,128 @@
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:51:5
+   |
+LL |     Tuple(get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+   |
+   = note: `-D clippy::unnecessary-operation` implied by `-D warnings`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:52:5
+   |
+LL |     Struct { field: get_number() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:53:5
+   |
+LL |     Struct { ..get_struct() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:54:5
+   |
+LL |     Enum::Tuple(get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:55:5
+   |
+LL |     Enum::Struct { field: get_number() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:56:5
+   |
+LL |     5 + get_number();
+   |     ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:57:5
+   |
+LL |     *&get_number();
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:58:5
+   |
+LL |     &get_number();
+   |     ^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:59:5
+   |
+LL |     (5, 6, get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:60:5
+   |
+LL |     box get_number();
+   |     ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:61:5
+   |
+LL |     get_number()..;
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:62:5
+   |
+LL |     ..get_number();
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:63:5
+   |
+LL |     5..get_number();
+   |     ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:64:5
+   |
+LL |     [42, get_number()];
+   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:65:5
+   |
+LL |     [42, 55][get_usize()];
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_usize();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:66:5
+   |
+LL |     (42, get_number()).1;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:67:5
+   |
+LL |     [get_number(); 55];
+   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:68:5
+   |
+LL |     [42; 55][get_usize()];
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_usize();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:69:5
+   |
+LL | /     {
+LL | |         get_number()
+LL | |     };
+   | |______^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:72:5
+   |
+LL | /     FooString {
+LL | |         s: String::from("blah"),
+LL | |     };
+   | |______^ help: replace it with: `String::from("blah");`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.fixed b/src/tools/clippy/tests/ui/unnecessary_ref.fixed
new file mode 100644
index 00000000000..f7b94118d4e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_ref.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![feature(stmt_expr_attributes)]
+#![allow(unused_variables)]
+
+struct Outer {
+    inner: u32,
+}
+
+#[deny(clippy::ref_in_deref)]
+fn main() {
+    let outer = Outer { inner: 0 };
+    let inner = outer.inner;
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.rs b/src/tools/clippy/tests/ui/unnecessary_ref.rs
new file mode 100644
index 00000000000..4e585b9b96b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_ref.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![feature(stmt_expr_attributes)]
+#![allow(unused_variables)]
+
+struct Outer {
+    inner: u32,
+}
+
+#[deny(clippy::ref_in_deref)]
+fn main() {
+    let outer = Outer { inner: 0 };
+    let inner = (&outer).inner;
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.stderr b/src/tools/clippy/tests/ui/unnecessary_ref.stderr
new file mode 100644
index 00000000000..34ba167a947
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_ref.stderr
@@ -0,0 +1,14 @@
+error: Creating a reference that is immediately dereferenced.
+  --> $DIR/unnecessary_ref.rs:13:17
+   |
+LL |     let inner = (&outer).inner;
+   |                 ^^^^^^^^ help: try this: `outer`
+   |
+note: the lint level is defined here
+  --> $DIR/unnecessary_ref.rs:10:8
+   |
+LL | #[deny(clippy::ref_in_deref)]
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
new file mode 100644
index 00000000000..fa639aa70d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
@@ -0,0 +1,22 @@
+#![warn(clippy::unneeded_field_pattern)]
+#[allow(dead_code, unused)]
+
+struct Foo {
+    a: i32,
+    b: i32,
+    c: i32,
+}
+
+fn main() {
+    let f = Foo { a: 0, b: 0, c: 0 };
+
+    match f {
+        Foo { a: _, b: 0, .. } => {},
+
+        Foo { a: _, b: _, c: _ } => {},
+    }
+    match f {
+        Foo { b: 0, .. } => {}, // should be OK
+        Foo { .. } => {},       // and the Force might be with this one
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
new file mode 100644
index 00000000000..e7b92ce1e19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
@@ -0,0 +1,19 @@
+error: You matched a field with a wildcard pattern. Consider using `..` instead
+  --> $DIR/unneeded_field_pattern.rs:14:15
+   |
+LL |         Foo { a: _, b: 0, .. } => {},
+   |               ^^^^
+   |
+   = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings`
+   = help: Try with `Foo { b: 0, .. }`
+
+error: All the struct fields are matched to a wildcard pattern, consider using `..`.
+  --> $DIR/unneeded_field_pattern.rs:16:9
+   |
+LL |         Foo { a: _, b: _, c: _ } => {},
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: Try with `Foo { .. }` instead
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed
new file mode 100644
index 00000000000..12c3461c955
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+#![deny(clippy::unneeded_wildcard_pattern)]
+
+fn main() {
+    let t = (0, 1, 2, 3);
+
+    if let (0, ..) = t {};
+    if let (0, ..) = t {};
+    if let (.., 0) = t {};
+    if let (.., 0) = t {};
+    if let (0, ..) = t {};
+    if let (0, ..) = t {};
+    if let (_, 0, ..) = t {};
+    if let (.., 0, _) = t {};
+    if let (0, _, _, _) = t {};
+    if let (0, ..) = t {};
+    if let (.., 0) = t {};
+
+    #[rustfmt::skip]
+    {
+        if let (0, ..,) = t {};
+    }
+
+    struct S(usize, usize, usize, usize);
+
+    let s = S(0, 1, 2, 3);
+
+    if let S(0, ..) = s {};
+    if let S(0, ..) = s {};
+    if let S(.., 0) = s {};
+    if let S(.., 0) = s {};
+    if let S(0, ..) = s {};
+    if let S(0, ..) = s {};
+    if let S(_, 0, ..) = s {};
+    if let S(.., 0, _) = s {};
+    if let S(0, _, _, _) = s {};
+    if let S(0, ..) = s {};
+    if let S(.., 0) = s {};
+
+    #[rustfmt::skip]
+    {
+        if let S(0, ..,) = s {};
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs
new file mode 100644
index 00000000000..4ac01d5d23b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+#![deny(clippy::unneeded_wildcard_pattern)]
+
+fn main() {
+    let t = (0, 1, 2, 3);
+
+    if let (0, .., _) = t {};
+    if let (0, _, ..) = t {};
+    if let (_, .., 0) = t {};
+    if let (.., _, 0) = t {};
+    if let (0, _, _, ..) = t {};
+    if let (0, .., _, _) = t {};
+    if let (_, 0, ..) = t {};
+    if let (.., 0, _) = t {};
+    if let (0, _, _, _) = t {};
+    if let (0, ..) = t {};
+    if let (.., 0) = t {};
+
+    #[rustfmt::skip]
+    {
+        if let (0, .., _, _,) = t {};
+    }
+
+    struct S(usize, usize, usize, usize);
+
+    let s = S(0, 1, 2, 3);
+
+    if let S(0, .., _) = s {};
+    if let S(0, _, ..) = s {};
+    if let S(_, .., 0) = s {};
+    if let S(.., _, 0) = s {};
+    if let S(0, _, _, ..) = s {};
+    if let S(0, .., _, _) = s {};
+    if let S(_, 0, ..) = s {};
+    if let S(.., 0, _) = s {};
+    if let S(0, _, _, _) = s {};
+    if let S(0, ..) = s {};
+    if let S(.., 0) = s {};
+
+    #[rustfmt::skip]
+    {
+        if let S(0, .., _, _,) = s {};
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr
new file mode 100644
index 00000000000..716d9ecff89
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr
@@ -0,0 +1,92 @@
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:8:18
+   |
+LL |     if let (0, .., _) = t {};
+   |                  ^^^ help: remove it
+   |
+note: the lint level is defined here
+  --> $DIR/unneeded_wildcard_pattern.rs:3:9
+   |
+LL | #![deny(clippy::unneeded_wildcard_pattern)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:9:16
+   |
+LL |     if let (0, _, ..) = t {};
+   |                ^^^ help: remove it
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:10:13
+   |
+LL |     if let (_, .., 0) = t {};
+   |             ^^^ help: remove it
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:11:15
+   |
+LL |     if let (.., _, 0) = t {};
+   |               ^^^ help: remove it
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:12:16
+   |
+LL |     if let (0, _, _, ..) = t {};
+   |                ^^^^^^ help: remove them
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:13:18
+   |
+LL |     if let (0, .., _, _) = t {};
+   |                  ^^^^^^ help: remove them
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:22:22
+   |
+LL |         if let (0, .., _, _,) = t {};
+   |                      ^^^^^^ help: remove them
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:29:19
+   |
+LL |     if let S(0, .., _) = s {};
+   |                   ^^^ help: remove it
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:30:17
+   |
+LL |     if let S(0, _, ..) = s {};
+   |                 ^^^ help: remove it
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:31:14
+   |
+LL |     if let S(_, .., 0) = s {};
+   |              ^^^ help: remove it
+
+error: this pattern is unneeded as the `..` pattern can match that element
+  --> $DIR/unneeded_wildcard_pattern.rs:32:16
+   |
+LL |     if let S(.., _, 0) = s {};
+   |                ^^^ help: remove it
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:33:17
+   |
+LL |     if let S(0, _, _, ..) = s {};
+   |                 ^^^^^^ help: remove them
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:34:19
+   |
+LL |     if let S(0, .., _, _) = s {};
+   |                   ^^^^^^ help: remove them
+
+error: these patterns are unneeded as the `..` pattern can match those elements
+  --> $DIR/unneeded_wildcard_pattern.rs:43:23
+   |
+LL |         if let S(0, .., _, _,) = s {};
+   |                       ^^^^^^ help: remove them
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed
new file mode 100644
index 00000000000..3f358d9ecaa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![warn(clippy::unreadable_literal)]
+
+struct Foo(u64);
+
+macro_rules! foo {
+    () => {
+        Foo(123123123123)
+    };
+}
+
+fn main() {
+    let _good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        65536,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let _bad = (0b11_0110_i64, 0xcafe_babe_usize, 123_456_f32, 1.234_567_f32);
+    let _good_sci = 1.1234e1;
+    let _bad_sci = 1.123_456e1;
+
+    let _fail9 = 0x00ab_cdef;
+    let _fail10: u32 = 0xBAFE_BAFE;
+    let _fail11 = 0x0abc_deff;
+    let _fail12: i128 = 0x00ab_cabc_abca_bcab_cabc;
+
+    let _ = foo!();
+}
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.rs b/src/tools/clippy/tests/ui/unreadable_literal.rs
new file mode 100644
index 00000000000..e658a5f28c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unreadable_literal.rs
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![warn(clippy::unreadable_literal)]
+
+struct Foo(u64);
+
+macro_rules! foo {
+    () => {
+        Foo(123123123123)
+    };
+}
+
+fn main() {
+    let _good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        65536,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32);
+    let _good_sci = 1.1234e1;
+    let _bad_sci = 1.123456e1;
+
+    let _fail9 = 0xabcdef;
+    let _fail10: u32 = 0xBAFEBAFE;
+    let _fail11 = 0xabcdeff;
+    let _fail12: i128 = 0xabcabcabcabcabcabc;
+
+    let _ = foo!();
+}
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr
new file mode 100644
index 00000000000..1b2ff6bff04
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr
@@ -0,0 +1,58 @@
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:25:17
+   |
+LL |     let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32);
+   |                 ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
+   |
+   = note: `-D clippy::unreadable-literal` implied by `-D warnings`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:25:31
+   |
+LL |     let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32);
+   |                               ^^^^^^^^^^^^^^^^ help: consider: `0xcafe_babe_usize`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:25:49
+   |
+LL |     let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32);
+   |                                                 ^^^^^^^^^^ help: consider: `123_456_f32`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:25:61
+   |
+LL |     let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32);
+   |                                                             ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:27:20
+   |
+LL |     let _bad_sci = 1.123456e1;
+   |                    ^^^^^^^^^^ help: consider: `1.123_456e1`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:29:18
+   |
+LL |     let _fail9 = 0xabcdef;
+   |                  ^^^^^^^^ help: consider: `0x00ab_cdef`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:30:24
+   |
+LL |     let _fail10: u32 = 0xBAFEBAFE;
+   |                        ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:31:19
+   |
+LL |     let _fail11 = 0xabcdeff;
+   |                   ^^^^^^^^^ help: consider: `0x0abc_deff`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:32:25
+   |
+LL |     let _fail12: i128 = 0xabcabcabcabcabcabc;
+   |                         ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
new file mode 100644
index 00000000000..7bee9c499e1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::unsafe_derive_deserialize)]
+#![allow(unused, clippy::missing_safety_doc)]
+
+extern crate serde;
+
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+pub struct A {}
+impl A {
+    pub unsafe fn new(_a: i32, _b: i32) -> Self {
+        Self {}
+    }
+}
+
+#[derive(Deserialize)]
+pub struct B {}
+impl B {
+    pub unsafe fn unsafe_method(&self) {}
+}
+
+#[derive(Deserialize)]
+pub struct C {}
+impl C {
+    pub fn unsafe_block(&self) {
+        unsafe {}
+    }
+}
+
+#[derive(Deserialize)]
+pub struct D {}
+impl D {
+    pub fn inner_unsafe_fn(&self) {
+        unsafe fn inner() {}
+    }
+}
+
+// Does not derive `Deserialize`, should be ignored
+pub struct E {}
+impl E {
+    pub unsafe fn new(_a: i32, _b: i32) -> Self {
+        Self {}
+    }
+
+    pub unsafe fn unsafe_method(&self) {}
+
+    pub fn unsafe_block(&self) {
+        unsafe {}
+    }
+
+    pub fn inner_unsafe_fn(&self) {
+        unsafe fn inner() {}
+    }
+}
+
+// Does not have methods using `unsafe`, should be ignored
+#[derive(Deserialize)]
+pub struct F {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
new file mode 100644
index 00000000000..1978bd95a67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
@@ -0,0 +1,39 @@
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+  --> $DIR/unsafe_derive_deserialize.rs:8:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+   = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings`
+   = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+  --> $DIR/unsafe_derive_deserialize.rs:16:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+   = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+  --> $DIR/unsafe_derive_deserialize.rs:22:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+   = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
+  --> $DIR/unsafe_derive_deserialize.rs:30:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+   = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
new file mode 100644
index 00000000000..a1f616733bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
@@ -0,0 +1,27 @@
+#![allow(unused_imports)]
+#![allow(dead_code)]
+#![warn(clippy::unsafe_removed_from_name)]
+
+use std::cell::UnsafeCell as TotallySafeCell;
+
+use std::cell::UnsafeCell as TotallySafeCellAgain;
+
+// Shouldn't error
+use std::cell::RefCell as ProbablyNotUnsafe;
+use std::cell::RefCell as RefCellThatCantBeUnsafe;
+use std::cell::UnsafeCell as SuperDangerousUnsafeCell;
+use std::cell::UnsafeCell as Dangerunsafe;
+use std::cell::UnsafeCell as Bombsawayunsafe;
+
+mod mod_with_some_unsafe_things {
+    pub struct Safe {}
+    pub struct Unsafe {}
+}
+
+use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
+
+// Shouldn't error
+use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime;
+use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr
new file mode 100644
index 00000000000..4f871cbe41b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr
@@ -0,0 +1,22 @@
+error: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCell`
+  --> $DIR/unsafe_removed_from_name.rs:5:1
+   |
+LL | use std::cell::UnsafeCell as TotallySafeCell;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings`
+
+error: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain`
+  --> $DIR/unsafe_removed_from_name.rs:7:1
+   |
+LL | use std::cell::UnsafeCell as TotallySafeCellAgain;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: removed `unsafe` from the name of `Unsafe` in use as `LieAboutModSafety`
+  --> $DIR/unsafe_removed_from_name.rs:21:1
+   |
+LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
new file mode 100644
index 00000000000..3c422cc4fee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
@@ -0,0 +1,41 @@
+// run-rustfix
+
+#![warn(clippy::unseparated_literal_suffix)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate clippy_mini_macro_test;
+
+// Test for proc-macro attribute
+#[derive(ClippyMiniMacroTest)]
+struct Foo;
+
+macro_rules! lit_from_macro {
+    () => {
+        42_usize
+    };
+}
+
+fn main() {
+    let _ok1 = 1234_i32;
+    let _ok2 = 1234_isize;
+    let _ok3 = 0x123_isize;
+    let _fail1 = 1234_i32;
+    let _fail2 = 1234_u32;
+    let _fail3 = 1234_isize;
+    let _fail4 = 1234_usize;
+    let _fail5 = 0x123_isize;
+
+    let _okf1 = 1.5_f32;
+    let _okf2 = 1_f32;
+    let _failf1 = 1.5_f32;
+    let _failf2 = 1_f32;
+
+    // Test for macro
+    let _ = lit_from_macro!();
+
+    // Counter example
+    let _ = line!();
+    // Because `assert!` contains `line!()` macro.
+    assert_eq!(4897_u32, 32223);
+}
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
new file mode 100644
index 00000000000..09608661e0e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
@@ -0,0 +1,41 @@
+// run-rustfix
+
+#![warn(clippy::unseparated_literal_suffix)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate clippy_mini_macro_test;
+
+// Test for proc-macro attribute
+#[derive(ClippyMiniMacroTest)]
+struct Foo;
+
+macro_rules! lit_from_macro {
+    () => {
+        42usize
+    };
+}
+
+fn main() {
+    let _ok1 = 1234_i32;
+    let _ok2 = 1234_isize;
+    let _ok3 = 0x123_isize;
+    let _fail1 = 1234i32;
+    let _fail2 = 1234u32;
+    let _fail3 = 1234isize;
+    let _fail4 = 1234usize;
+    let _fail5 = 0x123isize;
+
+    let _okf1 = 1.5_f32;
+    let _okf2 = 1_f32;
+    let _failf1 = 1.5f32;
+    let _failf2 = 1f32;
+
+    // Test for macro
+    let _ = lit_from_macro!();
+
+    // Counter example
+    let _ = line!();
+    // Because `assert!` contains `line!()` macro.
+    assert_eq!(4897u32, 32223);
+}
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
new file mode 100644
index 00000000000..d7dd526bcb9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
@@ -0,0 +1,63 @@
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:23:18
+   |
+LL |     let _fail1 = 1234i32;
+   |                  ^^^^^^^ help: add an underscore: `1234_i32`
+   |
+   = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:24:18
+   |
+LL |     let _fail2 = 1234u32;
+   |                  ^^^^^^^ help: add an underscore: `1234_u32`
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:25:18
+   |
+LL |     let _fail3 = 1234isize;
+   |                  ^^^^^^^^^ help: add an underscore: `1234_isize`
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:26:18
+   |
+LL |     let _fail4 = 1234usize;
+   |                  ^^^^^^^^^ help: add an underscore: `1234_usize`
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:27:18
+   |
+LL |     let _fail5 = 0x123isize;
+   |                  ^^^^^^^^^^ help: add an underscore: `0x123_isize`
+
+error: float type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:31:19
+   |
+LL |     let _failf1 = 1.5f32;
+   |                   ^^^^^^ help: add an underscore: `1.5_f32`
+
+error: float type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:32:19
+   |
+LL |     let _failf2 = 1f32;
+   |                   ^^^^ help: add an underscore: `1_f32`
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:15:9
+   |
+LL |         42usize
+   |         ^^^^^^^ help: add an underscore: `42_usize`
+...
+LL |     let _ = lit_from_macro!();
+   |             ----------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: integer type suffix should be separated by an underscore
+  --> $DIR/unseparated_prefix_literals.rs:40:16
+   |
+LL |     assert_eq!(4897u32, 32223);
+   |                ^^^^^^^ help: add an underscore: `4897_u32`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
new file mode 100644
index 00000000000..ebaba9629db
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -0,0 +1,25 @@
+#![allow(dead_code)]
+#![warn(clippy::unused_io_amount)]
+
+use std::io;
+
+fn question_mark<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
+    s.write(b"test")?;
+    let mut buf = [0u8; 4];
+    s.read(&mut buf)?;
+    Ok(())
+}
+
+fn unwrap<T: io::Read + io::Write>(s: &mut T) {
+    s.write(b"test").unwrap();
+    let mut buf = [0u8; 4];
+    s.read(&mut buf).unwrap();
+}
+
+fn vectored<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
+    s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?;
+    s.write_vectored(&[io::IoSlice::new(&[])])?;
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr
new file mode 100644
index 00000000000..5219d63980b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr
@@ -0,0 +1,40 @@
+error: written amount is not handled. Use `Write::write_all` instead
+  --> $DIR/unused_io_amount.rs:7:5
+   |
+LL |     s.write(b"test")?;
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unused-io-amount` implied by `-D warnings`
+
+error: read amount is not handled. Use `Read::read_exact` instead
+  --> $DIR/unused_io_amount.rs:9:5
+   |
+LL |     s.read(&mut buf)?;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: written amount is not handled. Use `Write::write_all` instead
+  --> $DIR/unused_io_amount.rs:14:5
+   |
+LL |     s.write(b"test").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: read amount is not handled. Use `Read::read_exact` instead
+  --> $DIR/unused_io_amount.rs:16:5
+   |
+LL |     s.read(&mut buf).unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:20:5
+   |
+LL |     s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:21:5
+   |
+LL |     s.write_vectored(&[io::IoSlice::new(&[])])?;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_self.rs b/src/tools/clippy/tests/ui/unused_self.rs
new file mode 100644
index 00000000000..7a4bbdda1ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_self.rs
@@ -0,0 +1,140 @@
+#![warn(clippy::unused_self)]
+#![allow(clippy::boxed_local, clippy::fn_params_excessive_bools)]
+
+mod unused_self {
+    use std::pin::Pin;
+    use std::sync::{Arc, Mutex};
+
+    struct A {}
+
+    impl A {
+        fn unused_self_move(self) {}
+        fn unused_self_ref(&self) {}
+        fn unused_self_mut_ref(&mut self) {}
+        fn unused_self_pin_ref(self: Pin<&Self>) {}
+        fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {}
+        fn unused_self_pin_nested(self: Pin<Arc<Self>>) {}
+        fn unused_self_box(self: Box<Self>) {}
+        fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 {
+            x + y
+        }
+        fn unused_self_class_method(&self) {
+            Self::static_method();
+        }
+
+        fn static_method() {}
+    }
+}
+
+mod unused_self_allow {
+    struct A {}
+
+    impl A {
+        // shouldn't trigger
+        #[allow(clippy::unused_self)]
+        fn unused_self_move(self) {}
+    }
+
+    struct B {}
+
+    // shouldn't trigger
+    #[allow(clippy::unused_self)]
+    impl B {
+        fn unused_self_move(self) {}
+    }
+
+    struct C {}
+
+    #[allow(clippy::unused_self)]
+    impl C {
+        #[warn(clippy::unused_self)]
+        fn some_fn((): ()) {}
+
+        // shouldn't trigger
+        fn unused_self_move(self) {}
+    }
+}
+
+mod used_self {
+    use std::pin::Pin;
+
+    struct A {
+        x: u8,
+    }
+
+    impl A {
+        fn used_self_move(self) -> u8 {
+            self.x
+        }
+        fn used_self_ref(&self) -> u8 {
+            self.x
+        }
+        fn used_self_mut_ref(&mut self) {
+            self.x += 1
+        }
+        fn used_self_pin_ref(self: Pin<&Self>) -> u8 {
+            self.x
+        }
+        fn used_self_box(self: Box<Self>) -> u8 {
+            self.x
+        }
+        fn used_self_with_other_unused_args(&self, x: u8, y: u8) -> u8 {
+            self.x
+        }
+        fn used_in_nested_closure(&self) -> u8 {
+            let mut a = || -> u8 { self.x };
+            a()
+        }
+
+        #[allow(clippy::collapsible_if)]
+        fn used_self_method_nested_conditions(&self, a: bool, b: bool, c: bool, d: bool) {
+            if a {
+                if b {
+                    if c {
+                        if d {
+                            self.used_self_ref();
+                        }
+                    }
+                }
+            }
+        }
+
+        fn foo(&self) -> u32 {
+            let mut sum = 0u32;
+            for i in 0..self.x {
+                sum += i as u32;
+            }
+            sum
+        }
+
+        fn bar(&mut self, x: u8) -> u32 {
+            let mut y = 0u32;
+            for i in 0..x {
+                y += self.foo()
+            }
+            y
+        }
+    }
+}
+
+mod not_applicable {
+    use std::fmt;
+
+    struct A {}
+
+    impl fmt::Debug for A {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            write!(f, "A")
+        }
+    }
+
+    impl A {
+        fn method(x: u8, y: u8) {}
+    }
+
+    trait B {
+        fn method(&self) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr
new file mode 100644
index 00000000000..0534b40eabb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_self.stderr
@@ -0,0 +1,75 @@
+error: unused `self` argument
+  --> $DIR/unused_self.rs:11:29
+   |
+LL |         fn unused_self_move(self) {}
+   |                             ^^^^
+   |
+   = note: `-D clippy::unused-self` implied by `-D warnings`
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:12:28
+   |
+LL |         fn unused_self_ref(&self) {}
+   |                            ^^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:13:32
+   |
+LL |         fn unused_self_mut_ref(&mut self) {}
+   |                                ^^^^^^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:14:32
+   |
+LL |         fn unused_self_pin_ref(self: Pin<&Self>) {}
+   |                                ^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:15:36
+   |
+LL |         fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {}
+   |                                    ^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:16:35
+   |
+LL |         fn unused_self_pin_nested(self: Pin<Arc<Self>>) {}
+   |                                   ^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:17:28
+   |
+LL |         fn unused_self_box(self: Box<Self>) {}
+   |                            ^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:18:40
+   |
+LL |         fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 {
+   |                                        ^^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: unused `self` argument
+  --> $DIR/unused_self.rs:21:37
+   |
+LL |         fn unused_self_class_method(&self) {
+   |                                     ^^^^^
+   |
+   = help: consider refactoring to a associated function
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed
new file mode 100644
index 00000000000..3f63624720f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.fixed
@@ -0,0 +1,59 @@
+// run-rustfix
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+
+struct Unitter;
+impl Unitter {
+    // try to disorient the lint with multiple unit returns and newlines
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) 
+    where G: Fn() -> () {
+        let _y: &dyn Fn() -> () = &f;
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self)  {
+        
+    }
+}
+
+fn return_unit()  {  }
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+    }
+    return;
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
new file mode 100644
index 00000000000..8fc072ebd69
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -0,0 +1,60 @@
+// run-rustfix
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+
+struct Unitter;
+impl Unitter {
+    // try to disorient the lint with multiple unit returns and newlines
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) ->
+        ()
+    where G: Fn() -> () {
+        let _y: &dyn Fn() -> () = &f;
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) -> () {
+        ()
+    }
+}
+
+fn return_unit() -> () { () }
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break();
+    }
+    return();
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr
new file mode 100644
index 00000000000..a013d2b3495
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.stderr
@@ -0,0 +1,52 @@
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:19:59
+   |
+LL |       pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) ->
+   |  ___________________________________________________________^
+LL | |         ()
+   | |__________^ help: remove the `-> ()`
+   |
+note: the lint level is defined here
+  --> $DIR/unused_unit.rs:12:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:29:19
+   |
+LL |     fn into(self) -> () {
+   |                   ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit expression
+  --> $DIR/unused_unit.rs:30:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:34:18
+   |
+LL | fn return_unit() -> () { () }
+   |                  ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit expression
+  --> $DIR/unused_unit.rs:34:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded `()`
+  --> $DIR/unused_unit.rs:44:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> $DIR/unused_unit.rs:46:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unwrap.rs b/src/tools/clippy/tests/ui/unwrap.rs
new file mode 100644
index 00000000000..fcd1fcd14d4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap.rs
@@ -0,0 +1,16 @@
+#![warn(clippy::option_unwrap_used, clippy::result_unwrap_used)]
+
+fn unwrap_option() {
+    let opt = Some(0);
+    let _ = opt.unwrap();
+}
+
+fn unwrap_result() {
+    let res: Result<u8, ()> = Ok(0);
+    let _ = res.unwrap();
+}
+
+fn main() {
+    unwrap_option();
+    unwrap_result();
+}
diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr
new file mode 100644
index 00000000000..b90ce68fa97
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap.stderr
@@ -0,0 +1,20 @@
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap.rs:5:13
+   |
+LL |     let _ = opt.unwrap();
+   |             ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-unwrap-used` implied by `-D warnings`
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: used `unwrap()` on `a Result` value
+  --> $DIR/unwrap.rs:10:13
+   |
+LL |     let _ = res.unwrap();
+   |             ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::result-unwrap-used` implied by `-D warnings`
+   = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unwrap_or.rs b/src/tools/clippy/tests/ui/unwrap_or.rs
new file mode 100644
index 00000000000..bfb41e43947
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_or.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::all)]
+
+fn main() {
+    let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+}
+
+fn new_lines() {
+    let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_or.stderr b/src/tools/clippy/tests/ui/unwrap_or.stderr
new file mode 100644
index 00000000000..c3a7464fd47
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_or.stderr
@@ -0,0 +1,16 @@
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/unwrap_or.rs:4:47
+   |
+LL |     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+   |
+   = note: `-D clippy::or-fun-call` implied by `-D warnings`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/unwrap_or.rs:8:47
+   |
+LL |     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/update-all-references.sh b/src/tools/clippy/tests/ui/update-all-references.sh
new file mode 100755
index 00000000000..30ba9188db4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/update-all-references.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# A script to update the references for all tests. The idea is that
+# you do a run, which will generate files in the build directory
+# containing the (normalized) actual output of the compiler. You then
+# run this script, which will copy those files over. If you find
+# yourself manually editing a foo.stderr file, you're doing it wrong.
+#
+# See all `update-references.sh`, if you just want to update a single test.
+
+if [[ "$1" == "--help" || "$1" == "-h" ]]; then
+    echo "usage: $0"
+fi
+
+CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-$PWD/target}
+PROFILE=${PROFILE:-debug}
+BUILD_DIR=${CARGO_TARGET_DIR}/${PROFILE}/test_build_base
+
+MY_DIR=$(dirname "$0")
+cd "$MY_DIR" || exit
+find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} +
diff --git a/src/tools/clippy/tests/ui/update-references.sh b/src/tools/clippy/tests/ui/update-references.sh
new file mode 100755
index 00000000000..2c13c327d79
--- /dev/null
+++ b/src/tools/clippy/tests/ui/update-references.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# A script to update the references for particular tests. The idea is
+# that you do a run, which will generate files in the build directory
+# containing the (normalized) actual output of the compiler. This
+# script will then copy that output and replace the "expected output"
+# files. You can then commit the changes.
+#
+# If you find yourself manually editing a `foo.stderr` file, you're
+# doing it wrong.
+
+if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
+    echo "usage: $0 <build-directory> <relative-path-to-rs-files>"
+    echo ""
+    echo "For example:"
+    echo "   $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
+fi
+
+MYDIR=$(dirname "$0")
+
+BUILD_DIR="$1"
+shift
+
+while [[ "$1" != "" ]]; do
+    STDERR_NAME="${1/%.rs/.stderr}"
+    STDOUT_NAME="${1/%.rs/.stdout}"
+    FIXED_NAME="${1/%.rs/.fixed}"
+    shift
+    if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \
+           ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then
+        echo updating "$MYDIR"/"$STDOUT_NAME"
+        cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"
+    fi
+    if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \
+           ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then
+        echo updating "$MYDIR"/"$STDERR_NAME"
+        cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"
+    fi
+    if [[ -f "$BUILD_DIR"/"$FIXED_NAME" ]] && \
+           ! (cmp -s -- "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME"); then
+        echo updating "$MYDIR"/"$FIXED_NAME"
+        cp "$BUILD_DIR"/"$FIXED_NAME" "$MYDIR"/"$FIXED_NAME"
+    fi
+done
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
new file mode 100644
index 00000000000..ebb3aa28daf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -0,0 +1,253 @@
+// run-rustfix
+// edition:2018
+
+#![warn(clippy::use_self)]
+#![allow(dead_code)]
+#![allow(clippy::should_implement_trait)]
+
+fn main() {}
+
+mod use_self {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Self {
+            Self {}
+        }
+        fn test() -> Self {
+            Self::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+}
+
+mod better {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Self {
+            Self {}
+        }
+        fn test() -> Self {
+            Self::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+}
+
+mod lifetimes {
+    struct Foo<'a> {
+        foo_str: &'a str,
+    }
+
+    impl<'a> Foo<'a> {
+        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
+        // Foo<'b>`
+        fn foo(s: &str) -> Foo {
+            Foo { foo_str: s }
+        }
+        // cannot replace with `Self`, because that's `Foo<'a>`
+        fn bar() -> Foo<'static> {
+            Foo { foo_str: "foo" }
+        }
+
+        // FIXME: the lint does not handle lifetimed struct
+        // `Self` should be applicable here
+        fn clone(&self) -> Foo<'a> {
+            Foo { foo_str: self.foo_str }
+        }
+    }
+}
+
+mod issue2894 {
+    trait IntoBytes {
+        fn into_bytes(&self) -> Vec<u8>;
+    }
+
+    // This should not be linted
+    impl IntoBytes for u8 {
+        fn into_bytes(&self) -> Vec<u8> {
+            vec![*self]
+        }
+    }
+}
+
+mod existential {
+    struct Foo;
+
+    impl Foo {
+        fn bad(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+
+        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+    }
+}
+
+mod tuple_structs {
+    pub struct TS(i32);
+
+    impl TS {
+        pub fn ts() -> Self {
+            Self(0)
+        }
+    }
+}
+
+mod macros {
+    macro_rules! use_self_expand {
+        () => {
+            fn new() -> Self {
+                Self {}
+            }
+        };
+    }
+
+    struct Foo {}
+
+    impl Foo {
+        use_self_expand!(); // Should lint in local macros
+    }
+}
+
+mod nesting {
+    struct Foo {}
+    impl Foo {
+        fn foo() {
+            #[allow(unused_imports)]
+            use self::Foo; // Can't use Self here
+            struct Bar {
+                foo: Foo, // Foo != Self
+            }
+
+            impl Bar {
+                fn bar() -> Self {
+                    Self { foo: Foo {} }
+                }
+            }
+
+            // Can't use Self here
+            fn baz() -> Foo {
+                Foo {}
+            }
+        }
+
+        // Should lint here
+        fn baz() -> Self {
+            Self {}
+        }
+    }
+
+    enum Enum {
+        A,
+        B(u64),
+        C { field: bool },
+    }
+    impl Enum {
+        fn method() {
+            #[allow(unused_imports)]
+            use self::Enum::*; // Issue 3425
+            static STATIC: Enum = Enum::A; // Can't use Self as type
+        }
+
+        fn method2() {
+            let _ = Self::B(42);
+            let _ = Self::C { field: true };
+            let _ = Self::A;
+        }
+    }
+}
+
+mod issue3410 {
+
+    struct A;
+    struct B;
+
+    trait Trait<T> {
+        fn a(v: T);
+    }
+
+    impl Trait<Vec<A>> for Vec<B> {
+        fn a(_: Vec<A>) {}
+    }
+}
+
+#[allow(clippy::no_effect, path_statements)]
+mod rustfix {
+    mod nested {
+        pub struct A {}
+    }
+
+    impl nested::A {
+        const A: bool = true;
+
+        fn fun_1() {}
+
+        fn fun_2() {
+            Self::fun_1();
+            Self::A;
+
+            Self {};
+        }
+    }
+}
+
+mod issue3567 {
+    struct TestStruct {}
+    impl TestStruct {
+        fn from_something() -> Self {
+            Self {}
+        }
+    }
+
+    trait Test {
+        fn test() -> TestStruct;
+    }
+
+    impl Test for TestStruct {
+        fn test() -> TestStruct {
+            Self::from_something()
+        }
+    }
+}
+
+mod paths_created_by_lowering {
+    use std::ops::Range;
+
+    struct S {}
+
+    impl S {
+        const A: usize = 0;
+        const B: usize = 1;
+
+        async fn g() -> Self {
+            Self {}
+        }
+
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
+            &p[Self::A..Self::B]
+        }
+    }
+
+    trait T {
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
+    }
+
+    impl T for Range<u8> {
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
+            &p[0..1]
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
new file mode 100644
index 00000000000..8a182192ab3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -0,0 +1,253 @@
+// run-rustfix
+// edition:2018
+
+#![warn(clippy::use_self)]
+#![allow(dead_code)]
+#![allow(clippy::should_implement_trait)]
+
+fn main() {}
+
+mod use_self {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Foo {
+            Foo {}
+        }
+        fn test() -> Foo {
+            Foo::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Foo {
+            Foo::new()
+        }
+    }
+}
+
+mod better {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Self {
+            Self {}
+        }
+        fn test() -> Self {
+            Self::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+}
+
+mod lifetimes {
+    struct Foo<'a> {
+        foo_str: &'a str,
+    }
+
+    impl<'a> Foo<'a> {
+        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
+        // Foo<'b>`
+        fn foo(s: &str) -> Foo {
+            Foo { foo_str: s }
+        }
+        // cannot replace with `Self`, because that's `Foo<'a>`
+        fn bar() -> Foo<'static> {
+            Foo { foo_str: "foo" }
+        }
+
+        // FIXME: the lint does not handle lifetimed struct
+        // `Self` should be applicable here
+        fn clone(&self) -> Foo<'a> {
+            Foo { foo_str: self.foo_str }
+        }
+    }
+}
+
+mod issue2894 {
+    trait IntoBytes {
+        fn into_bytes(&self) -> Vec<u8>;
+    }
+
+    // This should not be linted
+    impl IntoBytes for u8 {
+        fn into_bytes(&self) -> Vec<u8> {
+            vec![*self]
+        }
+    }
+}
+
+mod existential {
+    struct Foo;
+
+    impl Foo {
+        fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
+            foos.iter()
+        }
+
+        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+    }
+}
+
+mod tuple_structs {
+    pub struct TS(i32);
+
+    impl TS {
+        pub fn ts() -> Self {
+            TS(0)
+        }
+    }
+}
+
+mod macros {
+    macro_rules! use_self_expand {
+        () => {
+            fn new() -> Foo {
+                Foo {}
+            }
+        };
+    }
+
+    struct Foo {}
+
+    impl Foo {
+        use_self_expand!(); // Should lint in local macros
+    }
+}
+
+mod nesting {
+    struct Foo {}
+    impl Foo {
+        fn foo() {
+            #[allow(unused_imports)]
+            use self::Foo; // Can't use Self here
+            struct Bar {
+                foo: Foo, // Foo != Self
+            }
+
+            impl Bar {
+                fn bar() -> Bar {
+                    Bar { foo: Foo {} }
+                }
+            }
+
+            // Can't use Self here
+            fn baz() -> Foo {
+                Foo {}
+            }
+        }
+
+        // Should lint here
+        fn baz() -> Foo {
+            Foo {}
+        }
+    }
+
+    enum Enum {
+        A,
+        B(u64),
+        C { field: bool },
+    }
+    impl Enum {
+        fn method() {
+            #[allow(unused_imports)]
+            use self::Enum::*; // Issue 3425
+            static STATIC: Enum = Enum::A; // Can't use Self as type
+        }
+
+        fn method2() {
+            let _ = Enum::B(42);
+            let _ = Enum::C { field: true };
+            let _ = Enum::A;
+        }
+    }
+}
+
+mod issue3410 {
+
+    struct A;
+    struct B;
+
+    trait Trait<T> {
+        fn a(v: T);
+    }
+
+    impl Trait<Vec<A>> for Vec<B> {
+        fn a(_: Vec<A>) {}
+    }
+}
+
+#[allow(clippy::no_effect, path_statements)]
+mod rustfix {
+    mod nested {
+        pub struct A {}
+    }
+
+    impl nested::A {
+        const A: bool = true;
+
+        fn fun_1() {}
+
+        fn fun_2() {
+            nested::A::fun_1();
+            nested::A::A;
+
+            nested::A {};
+        }
+    }
+}
+
+mod issue3567 {
+    struct TestStruct {}
+    impl TestStruct {
+        fn from_something() -> Self {
+            Self {}
+        }
+    }
+
+    trait Test {
+        fn test() -> TestStruct;
+    }
+
+    impl Test for TestStruct {
+        fn test() -> TestStruct {
+            TestStruct::from_something()
+        }
+    }
+}
+
+mod paths_created_by_lowering {
+    use std::ops::Range;
+
+    struct S {}
+
+    impl S {
+        const A: usize = 0;
+        const B: usize = 1;
+
+        async fn g() -> S {
+            S {}
+        }
+
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
+            &p[S::A..S::B]
+        }
+    }
+
+    trait T {
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
+    }
+
+    impl T for Range<u8> {
+        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
+            &p[0..1]
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
new file mode 100644
index 00000000000..b33928597c1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -0,0 +1,164 @@
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:14:21
+   |
+LL |         fn new() -> Foo {
+   |                     ^^^ help: use the applicable keyword: `Self`
+   |
+   = note: `-D clippy::use-self` implied by `-D warnings`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:15:13
+   |
+LL |             Foo {}
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:17:22
+   |
+LL |         fn test() -> Foo {
+   |                      ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:18:13
+   |
+LL |             Foo::new()
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:23:25
+   |
+LL |         fn default() -> Foo {
+   |                         ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:24:13
+   |
+LL |             Foo::new()
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:89:56
+   |
+LL |         fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
+   |                                                        ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:104:13
+   |
+LL |             TS(0)
+   |             ^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:112:25
+   |
+LL |             fn new() -> Foo {
+   |                         ^^^ help: use the applicable keyword: `Self`
+...
+LL |         use_self_expand!(); // Should lint in local macros
+   |         ------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:113:17
+   |
+LL |                 Foo {}
+   |                 ^^^ help: use the applicable keyword: `Self`
+...
+LL |         use_self_expand!(); // Should lint in local macros
+   |         ------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:148:21
+   |
+LL |         fn baz() -> Foo {
+   |                     ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:149:13
+   |
+LL |             Foo {}
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:136:29
+   |
+LL |                 fn bar() -> Bar {
+   |                             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:137:21
+   |
+LL |                     Bar { foo: Foo {} }
+   |                     ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:166:21
+   |
+LL |             let _ = Enum::B(42);
+   |                     ^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:167:21
+   |
+LL |             let _ = Enum::C { field: true };
+   |                     ^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:168:21
+   |
+LL |             let _ = Enum::A;
+   |                     ^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:199:13
+   |
+LL |             nested::A::fun_1();
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:200:13
+   |
+LL |             nested::A::A;
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:202:13
+   |
+LL |             nested::A {};
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:221:13
+   |
+LL |             TestStruct::from_something()
+   |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:235:25
+   |
+LL |         async fn g() -> S {
+   |                         ^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:236:13
+   |
+LL |             S {}
+   |             ^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:240:16
+   |
+LL |             &p[S::A..S::B]
+   |                ^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:240:22
+   |
+LL |             &p[S::A..S::B]
+   |                      ^ help: use the applicable keyword: `Self`
+
+error: aborting due to 25 previous errors
+
diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed
new file mode 100644
index 00000000000..1582ae114bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_trait.fixed
@@ -0,0 +1,114 @@
+// run-rustfix
+
+#![warn(clippy::use_self)]
+#![allow(dead_code)]
+#![allow(clippy::should_implement_trait, clippy::boxed_local)]
+
+use std::ops::Mul;
+
+trait SelfTrait {
+    fn refs(p1: &Self) -> &Self;
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self;
+    fn mut_refs(p1: &mut Self) -> &mut Self;
+    fn nested(p1: Box<Self>, p2: (&u8, &Self));
+    fn vals(r: Self) -> Self;
+}
+
+#[derive(Default)]
+struct Bad;
+
+impl SelfTrait for Bad {
+    fn refs(p1: &Self) -> &Self {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Self) -> &mut Self {
+        p1
+    }
+
+    fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
+
+    fn vals(_: Self) -> Self {
+        Self::default()
+    }
+}
+
+impl Mul for Bad {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self {
+        rhs
+    }
+}
+
+impl Clone for Bad {
+    fn clone(&self) -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct Good;
+
+impl SelfTrait for Good {
+    fn refs(p1: &Self) -> &Self {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Self) -> &mut Self {
+        p1
+    }
+
+    fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
+
+    fn vals(_: Self) -> Self {
+        Self::default()
+    }
+}
+
+impl Mul for Good {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self {
+        rhs
+    }
+}
+
+trait NameTrait {
+    fn refs(p1: &u8) -> &u8;
+    fn ref_refs<'a>(p1: &'a &'a u8) -> &'a &'a u8;
+    fn mut_refs(p1: &mut u8) -> &mut u8;
+    fn nested(p1: Box<u8>, p2: (&u8, &u8));
+    fn vals(p1: u8) -> u8;
+}
+
+// Using `Self` instead of the type name is OK
+impl NameTrait for u8 {
+    fn refs(p1: &Self) -> &Self {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Self) -> &mut Self {
+        p1
+    }
+
+    fn nested(_p1: Box<Self>, _p2: (&Self, &Self)) {}
+
+    fn vals(_: Self) -> Self {
+        Self::default()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs
new file mode 100644
index 00000000000..70667b9797e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_trait.rs
@@ -0,0 +1,114 @@
+// run-rustfix
+
+#![warn(clippy::use_self)]
+#![allow(dead_code)]
+#![allow(clippy::should_implement_trait, clippy::boxed_local)]
+
+use std::ops::Mul;
+
+trait SelfTrait {
+    fn refs(p1: &Self) -> &Self;
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self;
+    fn mut_refs(p1: &mut Self) -> &mut Self;
+    fn nested(p1: Box<Self>, p2: (&u8, &Self));
+    fn vals(r: Self) -> Self;
+}
+
+#[derive(Default)]
+struct Bad;
+
+impl SelfTrait for Bad {
+    fn refs(p1: &Bad) -> &Bad {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Bad) -> &mut Bad {
+        p1
+    }
+
+    fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
+
+    fn vals(_: Bad) -> Bad {
+        Bad::default()
+    }
+}
+
+impl Mul for Bad {
+    type Output = Bad;
+
+    fn mul(self, rhs: Bad) -> Bad {
+        rhs
+    }
+}
+
+impl Clone for Bad {
+    fn clone(&self) -> Self {
+        Bad
+    }
+}
+
+#[derive(Default)]
+struct Good;
+
+impl SelfTrait for Good {
+    fn refs(p1: &Self) -> &Self {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Self) -> &mut Self {
+        p1
+    }
+
+    fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
+
+    fn vals(_: Self) -> Self {
+        Self::default()
+    }
+}
+
+impl Mul for Good {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self {
+        rhs
+    }
+}
+
+trait NameTrait {
+    fn refs(p1: &u8) -> &u8;
+    fn ref_refs<'a>(p1: &'a &'a u8) -> &'a &'a u8;
+    fn mut_refs(p1: &mut u8) -> &mut u8;
+    fn nested(p1: Box<u8>, p2: (&u8, &u8));
+    fn vals(p1: u8) -> u8;
+}
+
+// Using `Self` instead of the type name is OK
+impl NameTrait for u8 {
+    fn refs(p1: &Self) -> &Self {
+        p1
+    }
+
+    fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+        p1
+    }
+
+    fn mut_refs(p1: &mut Self) -> &mut Self {
+        p1
+    }
+
+    fn nested(_p1: Box<Self>, _p2: (&Self, &Self)) {}
+
+    fn vals(_: Self) -> Self {
+        Self::default()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr
new file mode 100644
index 00000000000..4f2506cc119
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_trait.stderr
@@ -0,0 +1,94 @@
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:21:18
+   |
+LL |     fn refs(p1: &Bad) -> &Bad {
+   |                  ^^^ help: use the applicable keyword: `Self`
+   |
+   = note: `-D clippy::use-self` implied by `-D warnings`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:21:27
+   |
+LL |     fn refs(p1: &Bad) -> &Bad {
+   |                           ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:25:33
+   |
+LL |     fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
+   |                                 ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:25:49
+   |
+LL |     fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
+   |                                                 ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:29:26
+   |
+LL |     fn mut_refs(p1: &mut Bad) -> &mut Bad {
+   |                          ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:29:39
+   |
+LL |     fn mut_refs(p1: &mut Bad) -> &mut Bad {
+   |                                       ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:33:24
+   |
+LL |     fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
+   |                        ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:33:42
+   |
+LL |     fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
+   |                                          ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:35:16
+   |
+LL |     fn vals(_: Bad) -> Bad {
+   |                ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:35:24
+   |
+LL |     fn vals(_: Bad) -> Bad {
+   |                        ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:36:9
+   |
+LL |         Bad::default()
+   |         ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:41:19
+   |
+LL |     type Output = Bad;
+   |                   ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:43:23
+   |
+LL |     fn mul(self, rhs: Bad) -> Bad {
+   |                       ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:43:31
+   |
+LL |     fn mul(self, rhs: Bad) -> Bad {
+   |                               ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self_trait.rs:50:9
+   |
+LL |         Bad
+   |         ^^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs
new file mode 100644
index 00000000000..8e0243c49aa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs
@@ -0,0 +1,119 @@
+// edition:2018
+// aux-build:proc_macro_derive.rs
+
+#![feature(rustc_private)]
+#![warn(clippy::all)]
+#![allow(clippy::blacklisted_name)]
+#![warn(clippy::used_underscore_binding)]
+
+#[macro_use]
+extern crate proc_macro_derive;
+
+// This should not trigger the lint. There's underscore binding inside the external derive that
+// would trigger the `used_underscore_binding` lint.
+#[derive(DeriveSomething)]
+struct Baz;
+
+macro_rules! test_macro {
+    () => {{
+        let _foo = 42;
+        _foo + 1
+    }};
+}
+
+/// Tests that we lint if we use a binding with a single leading underscore
+fn prefix_underscore(_foo: u32) -> u32 {
+    _foo + 1
+}
+
+/// Tests that we lint if we use a `_`-variable defined outside within a macro expansion
+fn in_macro_or_desugar(_foo: u32) {
+    println!("{}", _foo);
+    assert_eq!(_foo, _foo);
+
+    test_macro!() + 1;
+}
+
+// Struct for testing use of fields prefixed with an underscore
+struct StructFieldTest {
+    _underscore_field: u32,
+}
+
+/// Tests that we lint the use of a struct field which is prefixed with an underscore
+fn in_struct_field() {
+    let mut s = StructFieldTest { _underscore_field: 0 };
+    s._underscore_field += 1;
+}
+
+/// Tests that we do not lint if the underscore is not a prefix
+fn non_prefix_underscore(some_foo: u32) -> u32 {
+    some_foo + 1
+}
+
+/// Tests that we do not lint if we do not use the binding (simple case)
+fn unused_underscore_simple(_foo: u32) -> u32 {
+    1
+}
+
+/// Tests that we do not lint if we do not use the binding (complex case). This checks for
+/// compatibility with the built-in `unused_variables` lint.
+fn unused_underscore_complex(mut _foo: u32) -> u32 {
+    _foo += 1;
+    _foo = 2;
+    1
+}
+
+/// Test that we do not lint for multiple underscores
+fn multiple_underscores(__foo: u32) -> u32 {
+    __foo + 1
+}
+
+// Non-variable bindings with preceding underscore
+fn _fn_test() {}
+struct _StructTest;
+enum _EnumTest {
+    _Empty,
+    _Value(_StructTest),
+}
+
+/// Tests that we do not lint for non-variable bindings
+fn non_variables() {
+    _fn_test();
+    let _s = _StructTest;
+    let _e = match _EnumTest::_Value(_StructTest) {
+        _EnumTest::_Empty => 0,
+        _EnumTest::_Value(_st) => 1,
+    };
+    let f = _fn_test;
+    f();
+}
+
+// Tests that we do not lint if the binding comes from await desugaring,
+// but we do lint the awaited expression. See issue 5360.
+async fn await_desugaring() {
+    async fn foo() {}
+    fn uses_i(_i: i32) {}
+
+    foo().await;
+    ({
+        let _i = 5;
+        uses_i(_i);
+        foo()
+    })
+    .await
+}
+
+fn main() {
+    let foo = 0u32;
+    // tests of unused_underscore lint
+    let _ = prefix_underscore(foo);
+    in_macro_or_desugar(foo);
+    in_struct_field();
+    // possible false positives
+    let _ = non_prefix_underscore(foo);
+    let _ = unused_underscore_simple(foo);
+    let _ = unused_underscore_complex(foo);
+    let _ = multiple_underscores(foo);
+    non_variables();
+    await_desugaring();
+}
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
new file mode 100644
index 00000000000..68e96148093
--- /dev/null
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
@@ -0,0 +1,40 @@
+error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:26:5
+   |
+LL |     _foo + 1
+   |     ^^^^
+   |
+   = note: `-D clippy::used-underscore-binding` implied by `-D warnings`
+
+error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:31:20
+   |
+LL |     println!("{}", _foo);
+   |                    ^^^^
+
+error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:32:16
+   |
+LL |     assert_eq!(_foo, _foo);
+   |                ^^^^
+
+error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:32:22
+   |
+LL |     assert_eq!(_foo, _foo);
+   |                      ^^^^
+
+error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:45:5
+   |
+LL |     s._underscore_field += 1;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
+  --> $DIR/used_underscore_binding.rs:100:16
+   |
+LL |         uses_i(_i);
+   |                ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useful_asref.rs b/src/tools/clippy/tests/ui/useful_asref.rs
new file mode 100644
index 00000000000..a9f0170a79c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useful_asref.rs
@@ -0,0 +1,13 @@
+#![deny(clippy::useless_asref)]
+
+trait Trait {
+    fn as_ptr(&self);
+}
+
+impl<'a> Trait for &'a [u8] {
+    fn as_ptr(&self) {
+        self.as_ref().as_ptr();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
new file mode 100644
index 00000000000..e356f13d087
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -0,0 +1,135 @@
+// run-rustfix
+
+#![deny(clippy::useless_asref)]
+
+use std::fmt::Debug;
+
+struct FakeAsRef;
+
+#[allow(clippy::should_implement_trait)]
+impl FakeAsRef {
+    fn as_ref(&self) -> &Self {
+        self
+    }
+}
+
+struct MoreRef;
+
+impl<'a, 'b, 'c> AsRef<&'a &'b &'c MoreRef> for MoreRef {
+    fn as_ref(&self) -> &&'a &'b &'c MoreRef {
+        &&&&MoreRef
+    }
+}
+
+fn foo_rstr(x: &str) {
+    println!("{:?}", x);
+}
+fn foo_rslice(x: &[i32]) {
+    println!("{:?}", x);
+}
+fn foo_mrslice(x: &mut [i32]) {
+    println!("{:?}", x);
+}
+fn foo_rrrrmr(_: &&&&MoreRef) {
+    println!("so many refs");
+}
+
+fn not_ok() {
+    let rstr: &str = "hello";
+    let mut mrslice: &mut [i32] = &mut [1, 2, 3];
+
+    {
+        let rslice: &[i32] = &*mrslice;
+        foo_rstr(rstr);
+        foo_rstr(rstr);
+        foo_rslice(rslice);
+        foo_rslice(rslice);
+    }
+    {
+        foo_mrslice(mrslice);
+        foo_mrslice(mrslice);
+        foo_rslice(mrslice);
+        foo_rslice(mrslice);
+    }
+
+    {
+        let rrrrrstr = &&&&rstr;
+        let rrrrrslice = &&&&&*mrslice;
+        foo_rslice(rrrrrslice);
+        foo_rslice(rrrrrslice);
+        foo_rstr(rrrrrstr);
+        foo_rstr(rrrrrstr);
+    }
+    {
+        let mrrrrrslice = &mut &mut &mut &mut mrslice;
+        foo_mrslice(mrrrrrslice);
+        foo_mrslice(mrrrrrslice);
+        foo_rslice(mrrrrrslice);
+        foo_rslice(mrrrrrslice);
+    }
+    #[allow(unused_parens, clippy::double_parens)]
+    foo_rrrrmr((&&&&MoreRef));
+
+    generic_not_ok(mrslice);
+    generic_ok(mrslice);
+}
+
+fn ok() {
+    let string = "hello".to_owned();
+    let mut arr = [1, 2, 3];
+    let mut vec = vec![1, 2, 3];
+
+    {
+        foo_rstr(string.as_ref());
+        foo_rslice(arr.as_ref());
+        foo_rslice(vec.as_ref());
+    }
+    {
+        foo_mrslice(arr.as_mut());
+        foo_mrslice(vec.as_mut());
+    }
+
+    {
+        let rrrrstring = &&&&string;
+        let rrrrarr = &&&&arr;
+        let rrrrvec = &&&&vec;
+        foo_rstr(rrrrstring.as_ref());
+        foo_rslice(rrrrarr.as_ref());
+        foo_rslice(rrrrvec.as_ref());
+    }
+    {
+        let mrrrrarr = &mut &mut &mut &mut arr;
+        let mrrrrvec = &mut &mut &mut &mut vec;
+        foo_mrslice(mrrrrarr.as_mut());
+        foo_mrslice(mrrrrvec.as_mut());
+    }
+    FakeAsRef.as_ref();
+    foo_rrrrmr(MoreRef.as_ref());
+
+    generic_not_ok(arr.as_mut());
+    generic_ok(&mut arr);
+}
+
+fn foo_mrt<T: Debug + ?Sized>(t: &mut T) {
+    println!("{:?}", t);
+}
+fn foo_rt<T: Debug + ?Sized>(t: &T) {
+    println!("{:?}", t);
+}
+
+fn generic_not_ok<T: AsMut<T> + AsRef<T> + Debug + ?Sized>(mrt: &mut T) {
+    foo_mrt(mrt);
+    foo_mrt(mrt);
+    foo_rt(mrt);
+    foo_rt(mrt);
+}
+
+fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
+    foo_mrt(mru.as_mut());
+    foo_rt(mru.as_ref());
+}
+
+fn main() {
+    not_ok();
+    ok();
+}
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
new file mode 100644
index 00000000000..2a80291f5d8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -0,0 +1,135 @@
+// run-rustfix
+
+#![deny(clippy::useless_asref)]
+
+use std::fmt::Debug;
+
+struct FakeAsRef;
+
+#[allow(clippy::should_implement_trait)]
+impl FakeAsRef {
+    fn as_ref(&self) -> &Self {
+        self
+    }
+}
+
+struct MoreRef;
+
+impl<'a, 'b, 'c> AsRef<&'a &'b &'c MoreRef> for MoreRef {
+    fn as_ref(&self) -> &&'a &'b &'c MoreRef {
+        &&&&MoreRef
+    }
+}
+
+fn foo_rstr(x: &str) {
+    println!("{:?}", x);
+}
+fn foo_rslice(x: &[i32]) {
+    println!("{:?}", x);
+}
+fn foo_mrslice(x: &mut [i32]) {
+    println!("{:?}", x);
+}
+fn foo_rrrrmr(_: &&&&MoreRef) {
+    println!("so many refs");
+}
+
+fn not_ok() {
+    let rstr: &str = "hello";
+    let mut mrslice: &mut [i32] = &mut [1, 2, 3];
+
+    {
+        let rslice: &[i32] = &*mrslice;
+        foo_rstr(rstr.as_ref());
+        foo_rstr(rstr);
+        foo_rslice(rslice.as_ref());
+        foo_rslice(rslice);
+    }
+    {
+        foo_mrslice(mrslice.as_mut());
+        foo_mrslice(mrslice);
+        foo_rslice(mrslice.as_ref());
+        foo_rslice(mrslice);
+    }
+
+    {
+        let rrrrrstr = &&&&rstr;
+        let rrrrrslice = &&&&&*mrslice;
+        foo_rslice(rrrrrslice.as_ref());
+        foo_rslice(rrrrrslice);
+        foo_rstr(rrrrrstr.as_ref());
+        foo_rstr(rrrrrstr);
+    }
+    {
+        let mrrrrrslice = &mut &mut &mut &mut mrslice;
+        foo_mrslice(mrrrrrslice.as_mut());
+        foo_mrslice(mrrrrrslice);
+        foo_rslice(mrrrrrslice.as_ref());
+        foo_rslice(mrrrrrslice);
+    }
+    #[allow(unused_parens, clippy::double_parens)]
+    foo_rrrrmr((&&&&MoreRef).as_ref());
+
+    generic_not_ok(mrslice);
+    generic_ok(mrslice);
+}
+
+fn ok() {
+    let string = "hello".to_owned();
+    let mut arr = [1, 2, 3];
+    let mut vec = vec![1, 2, 3];
+
+    {
+        foo_rstr(string.as_ref());
+        foo_rslice(arr.as_ref());
+        foo_rslice(vec.as_ref());
+    }
+    {
+        foo_mrslice(arr.as_mut());
+        foo_mrslice(vec.as_mut());
+    }
+
+    {
+        let rrrrstring = &&&&string;
+        let rrrrarr = &&&&arr;
+        let rrrrvec = &&&&vec;
+        foo_rstr(rrrrstring.as_ref());
+        foo_rslice(rrrrarr.as_ref());
+        foo_rslice(rrrrvec.as_ref());
+    }
+    {
+        let mrrrrarr = &mut &mut &mut &mut arr;
+        let mrrrrvec = &mut &mut &mut &mut vec;
+        foo_mrslice(mrrrrarr.as_mut());
+        foo_mrslice(mrrrrvec.as_mut());
+    }
+    FakeAsRef.as_ref();
+    foo_rrrrmr(MoreRef.as_ref());
+
+    generic_not_ok(arr.as_mut());
+    generic_ok(&mut arr);
+}
+
+fn foo_mrt<T: Debug + ?Sized>(t: &mut T) {
+    println!("{:?}", t);
+}
+fn foo_rt<T: Debug + ?Sized>(t: &T) {
+    println!("{:?}", t);
+}
+
+fn generic_not_ok<T: AsMut<T> + AsRef<T> + Debug + ?Sized>(mrt: &mut T) {
+    foo_mrt(mrt.as_mut());
+    foo_mrt(mrt);
+    foo_rt(mrt.as_ref());
+    foo_rt(mrt);
+}
+
+fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
+    foo_mrt(mru.as_mut());
+    foo_rt(mru.as_ref());
+}
+
+fn main() {
+    not_ok();
+    ok();
+}
diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr
new file mode 100644
index 00000000000..5876b54aca8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_asref.stderr
@@ -0,0 +1,74 @@
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:43:18
+   |
+LL |         foo_rstr(rstr.as_ref());
+   |                  ^^^^^^^^^^^^^ help: try this: `rstr`
+   |
+note: the lint level is defined here
+  --> $DIR/useless_asref.rs:3:9
+   |
+LL | #![deny(clippy::useless_asref)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:45:20
+   |
+LL |         foo_rslice(rslice.as_ref());
+   |                    ^^^^^^^^^^^^^^^ help: try this: `rslice`
+
+error: this call to `as_mut` does nothing
+  --> $DIR/useless_asref.rs:49:21
+   |
+LL |         foo_mrslice(mrslice.as_mut());
+   |                     ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:51:20
+   |
+LL |         foo_rslice(mrslice.as_ref());
+   |                    ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:58:20
+   |
+LL |         foo_rslice(rrrrrslice.as_ref());
+   |                    ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:60:18
+   |
+LL |         foo_rstr(rrrrrstr.as_ref());
+   |                  ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr`
+
+error: this call to `as_mut` does nothing
+  --> $DIR/useless_asref.rs:65:21
+   |
+LL |         foo_mrslice(mrrrrrslice.as_mut());
+   |                     ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:67:20
+   |
+LL |         foo_rslice(mrrrrrslice.as_ref());
+   |                    ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:71:16
+   |
+LL |     foo_rrrrmr((&&&&MoreRef).as_ref());
+   |                ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)`
+
+error: this call to `as_mut` does nothing
+  --> $DIR/useless_asref.rs:121:13
+   |
+LL |     foo_mrt(mrt.as_mut());
+   |             ^^^^^^^^^^^^ help: try this: `mrt`
+
+error: this call to `as_ref` does nothing
+  --> $DIR/useless_asref.rs:123:12
+   |
+LL |     foo_rt(mrt.as_ref());
+   |            ^^^^^^^^^^^^ help: try this: `mrt`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
new file mode 100644
index 00000000000..b222e2f7976
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -0,0 +1,61 @@
+// run-rustfix
+// aux-build:proc_macro_derive.rs
+
+#![warn(clippy::useless_attribute)]
+#![warn(unreachable_pub)]
+#![feature(rustc_private)]
+
+#![allow(dead_code)]
+#![cfg_attr(feature = "cargo-clippy", allow(dead_code))]
+#[rustfmt::skip]
+#[allow(unused_imports)]
+#[allow(unused_extern_crates)]
+#[macro_use]
+extern crate rustc_middle;
+
+#[macro_use]
+extern crate proc_macro_derive;
+
+// don't lint on unused_import for `use` items
+#[allow(unused_imports)]
+use std::collections;
+
+// don't lint on unused for `use` items
+#[allow(unused)]
+use std::option;
+
+// don't lint on deprecated for `use` items
+mod foo {
+    #[deprecated]
+    pub struct Bar;
+}
+#[allow(deprecated)]
+pub use foo::Bar;
+
+// This should not trigger the lint. There's lint level definitions inside the external derive
+// that would trigger the useless_attribute lint.
+#[derive(DeriveSomething)]
+struct Baz;
+
+// don't lint on unreachable_pub for `use` items
+mod a {
+    mod b {
+        #[allow(dead_code)]
+        #[allow(unreachable_pub)]
+        pub struct C {}
+    }
+
+    #[allow(unreachable_pub)]
+    pub use self::b::C;
+}
+
+fn test_indented_attr() {
+    #![allow(clippy::almost_swapped)]
+    use std::collections::HashSet;
+
+    let _ = HashSet::<u32>::default();
+}
+
+fn main() {
+    test_indented_attr();
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
new file mode 100644
index 00000000000..3422eace4ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -0,0 +1,61 @@
+// run-rustfix
+// aux-build:proc_macro_derive.rs
+
+#![warn(clippy::useless_attribute)]
+#![warn(unreachable_pub)]
+#![feature(rustc_private)]
+
+#[allow(dead_code)]
+#[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
+#[rustfmt::skip]
+#[allow(unused_imports)]
+#[allow(unused_extern_crates)]
+#[macro_use]
+extern crate rustc_middle;
+
+#[macro_use]
+extern crate proc_macro_derive;
+
+// don't lint on unused_import for `use` items
+#[allow(unused_imports)]
+use std::collections;
+
+// don't lint on unused for `use` items
+#[allow(unused)]
+use std::option;
+
+// don't lint on deprecated for `use` items
+mod foo {
+    #[deprecated]
+    pub struct Bar;
+}
+#[allow(deprecated)]
+pub use foo::Bar;
+
+// This should not trigger the lint. There's lint level definitions inside the external derive
+// that would trigger the useless_attribute lint.
+#[derive(DeriveSomething)]
+struct Baz;
+
+// don't lint on unreachable_pub for `use` items
+mod a {
+    mod b {
+        #[allow(dead_code)]
+        #[allow(unreachable_pub)]
+        pub struct C {}
+    }
+
+    #[allow(unreachable_pub)]
+    pub use self::b::C;
+}
+
+fn test_indented_attr() {
+    #[allow(clippy::almost_swapped)]
+    use std::collections::HashSet;
+
+    let _ = HashSet::<u32>::default();
+}
+
+fn main() {
+    test_indented_attr();
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.stderr b/src/tools/clippy/tests/ui/useless_attribute.stderr
new file mode 100644
index 00000000000..57ba976730c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_attribute.stderr
@@ -0,0 +1,22 @@
+error: useless lint attribute
+  --> $DIR/useless_attribute.rs:8:1
+   |
+LL | #[allow(dead_code)]
+   | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]`
+   |
+   = note: `-D clippy::useless-attribute` implied by `-D warnings`
+
+error: useless lint attribute
+  --> $DIR/useless_attribute.rs:9:1
+   |
+LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)`
+
+error: useless lint attribute
+  --> $DIR/useless_attribute.rs:53:5
+   |
+LL |     #[allow(clippy::almost_swapped)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
new file mode 100644
index 00000000000..e73a791891f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -0,0 +1,55 @@
+// run-rustfix
+
+#![warn(clippy::useless_vec)]
+
+#[derive(Debug)]
+struct NonCopy;
+
+fn on_slice(_: &[u8]) {}
+#[allow(clippy::ptr_arg)]
+fn on_vec(_: &Vec<u8>) {}
+
+struct Line {
+    length: usize,
+}
+
+impl Line {
+    fn length(&self) -> usize {
+        self.length
+    }
+}
+
+fn main() {
+    on_slice(&[]);
+    on_slice(&[]);
+
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+    #[rustfmt::skip]
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+
+    on_slice(&[1; 2]);
+    on_slice(&[1; 2]);
+
+    on_vec(&vec![]);
+    on_vec(&vec![1, 2]);
+    on_vec(&vec![1; 2]);
+
+    // Now with non-constant expressions
+    let line = Line { length: 2 };
+
+    on_slice(&vec![2; line.length]);
+    on_slice(&vec![2; line.length()]);
+
+    for a in &[1, 2, 3] {
+        println!("{:?}", a);
+    }
+
+    for a in vec![NonCopy, NonCopy] {
+        println!("{:?}", a);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
new file mode 100644
index 00000000000..3eb960f53d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -0,0 +1,55 @@
+// run-rustfix
+
+#![warn(clippy::useless_vec)]
+
+#[derive(Debug)]
+struct NonCopy;
+
+fn on_slice(_: &[u8]) {}
+#[allow(clippy::ptr_arg)]
+fn on_vec(_: &Vec<u8>) {}
+
+struct Line {
+    length: usize,
+}
+
+impl Line {
+    fn length(&self) -> usize {
+        self.length
+    }
+}
+
+fn main() {
+    on_slice(&vec![]);
+    on_slice(&[]);
+
+    on_slice(&vec![1, 2]);
+    on_slice(&[1, 2]);
+
+    on_slice(&vec![1, 2]);
+    on_slice(&[1, 2]);
+    #[rustfmt::skip]
+    on_slice(&vec!(1, 2));
+    on_slice(&[1, 2]);
+
+    on_slice(&vec![1; 2]);
+    on_slice(&[1; 2]);
+
+    on_vec(&vec![]);
+    on_vec(&vec![1, 2]);
+    on_vec(&vec![1; 2]);
+
+    // Now with non-constant expressions
+    let line = Line { length: 2 };
+
+    on_slice(&vec![2; line.length]);
+    on_slice(&vec![2; line.length()]);
+
+    for a in vec![1, 2, 3] {
+        println!("{:?}", a);
+    }
+
+    for a in vec![NonCopy, NonCopy] {
+        println!("{:?}", a);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr
new file mode 100644
index 00000000000..37e28ebddb5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec.stderr
@@ -0,0 +1,40 @@
+error: useless use of `vec!`
+  --> $DIR/vec.rs:23:14
+   |
+LL |     on_slice(&vec![]);
+   |              ^^^^^^^ help: you can use a slice directly: `&[]`
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:26:14
+   |
+LL |     on_slice(&vec![1, 2]);
+   |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:29:14
+   |
+LL |     on_slice(&vec![1, 2]);
+   |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:32:14
+   |
+LL |     on_slice(&vec!(1, 2));
+   |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:35:14
+   |
+LL |     on_slice(&vec![1; 2]);
+   |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
+
+error: useless use of `vec!`
+  --> $DIR/vec.rs:48:14
+   |
+LL |     for a in vec![1, 2, 3] {
+   |              ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.fixed b/src/tools/clippy/tests/ui/vec_box_sized.fixed
new file mode 100644
index 00000000000..d0bee2460dd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_box_sized.fixed
@@ -0,0 +1,38 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct SizedStruct(i32);
+struct UnsizedStruct([i32]);
+struct BigStruct([i32; 10000]);
+
+/// The following should trigger the lint
+mod should_trigger {
+    use super::SizedStruct;
+
+    struct StructWithVecBox {
+        sized_type: Vec<SizedStruct>,
+    }
+
+    struct A(Vec<SizedStruct>);
+    struct B(Vec<Vec<u32>>);
+}
+
+/// The following should not trigger the lint
+mod should_not_trigger {
+    use super::{BigStruct, UnsizedStruct};
+
+    struct C(Vec<Box<UnsizedStruct>>);
+    struct D(Vec<Box<BigStruct>>);
+
+    struct StructWithVecBoxButItsUnsized {
+        unsized_type: Vec<Box<UnsizedStruct>>,
+    }
+
+    struct TraitVec<T: ?Sized> {
+        // Regression test for #3720. This was causing an ICE.
+        inner: Vec<Box<T>>,
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.rs b/src/tools/clippy/tests/ui/vec_box_sized.rs
new file mode 100644
index 00000000000..500a0ae263e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_box_sized.rs
@@ -0,0 +1,38 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct SizedStruct(i32);
+struct UnsizedStruct([i32]);
+struct BigStruct([i32; 10000]);
+
+/// The following should trigger the lint
+mod should_trigger {
+    use super::SizedStruct;
+
+    struct StructWithVecBox {
+        sized_type: Vec<Box<SizedStruct>>,
+    }
+
+    struct A(Vec<Box<SizedStruct>>);
+    struct B(Vec<Vec<Box<(u32)>>>);
+}
+
+/// The following should not trigger the lint
+mod should_not_trigger {
+    use super::{BigStruct, UnsizedStruct};
+
+    struct C(Vec<Box<UnsizedStruct>>);
+    struct D(Vec<Box<BigStruct>>);
+
+    struct StructWithVecBoxButItsUnsized {
+        unsized_type: Vec<Box<UnsizedStruct>>,
+    }
+
+    struct TraitVec<T: ?Sized> {
+        // Regression test for #3720. This was causing an ICE.
+        inner: Vec<Box<T>>,
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/vec_box_sized.stderr b/src/tools/clippy/tests/ui/vec_box_sized.stderr
new file mode 100644
index 00000000000..29bf7069e8a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_box_sized.stderr
@@ -0,0 +1,22 @@
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:14:21
+   |
+LL |         sized_type: Vec<Box<SizedStruct>>,
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+   |
+   = note: `-D clippy::vec-box` implied by `-D warnings`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:17:14
+   |
+LL |     struct A(Vec<Box<SizedStruct>>);
+   |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:18:18
+   |
+LL |     struct B(Vec<Vec<Box<(u32)>>>);
+   |                  ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.rs b/src/tools/clippy/tests/ui/verbose_file_reads.rs
new file mode 100644
index 00000000000..e0065e05ade
--- /dev/null
+++ b/src/tools/clippy/tests/ui/verbose_file_reads.rs
@@ -0,0 +1,28 @@
+#![warn(clippy::verbose_file_reads)]
+use std::env::temp_dir;
+use std::fs::File;
+use std::io::Read;
+
+struct Struct;
+// To make sure we only warn on File::{read_to_end, read_to_string} calls
+impl Struct {
+    pub fn read_to_end(&self) {}
+
+    pub fn read_to_string(&self) {}
+}
+
+fn main() -> std::io::Result<()> {
+    let path = "foo.txt";
+    // Lint shouldn't catch this
+    let s = Struct;
+    s.read_to_end();
+    s.read_to_string();
+    // Should catch this
+    let mut f = File::open(&path)?;
+    let mut buffer = Vec::new();
+    f.read_to_end(&mut buffer)?;
+    // ...and this
+    let mut string_buffer = String::new();
+    f.read_to_string(&mut string_buffer)?;
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.stderr b/src/tools/clippy/tests/ui/verbose_file_reads.stderr
new file mode 100644
index 00000000000..550b6ab679f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/verbose_file_reads.stderr
@@ -0,0 +1,19 @@
+error: use of `File::read_to_end`
+  --> $DIR/verbose_file_reads.rs:23:5
+   |
+LL |     f.read_to_end(&mut buffer)?;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::verbose-file-reads` implied by `-D warnings`
+   = help: consider using `fs::read` instead
+
+error: use of `File::read_to_string`
+  --> $DIR/verbose_file_reads.rs:26:5
+   |
+LL |     f.read_to_string(&mut string_buffer)?;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using `fs::read_to_string` instead
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.rs b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs
new file mode 100644
index 00000000000..c91d96ee18a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.rs
@@ -0,0 +1,42 @@
+use std::fmt::Debug;
+use std::ptr;
+use std::rc::Rc;
+use std::sync::Arc;
+
+#[warn(clippy::vtable_address_comparisons)]
+fn main() {
+    let a: *const dyn Debug = &1 as &dyn Debug;
+    let b: *const dyn Debug = &1 as &dyn Debug;
+
+    // These should fail:
+    let _ = a == b;
+    let _ = a != b;
+    let _ = a < b;
+    let _ = a <= b;
+    let _ = a > b;
+    let _ = a >= b;
+    ptr::eq(a, b);
+
+    let a = &1 as &dyn Debug;
+    let b = &1 as &dyn Debug;
+    ptr::eq(a, b);
+
+    let a: Rc<dyn Debug> = Rc::new(1);
+    Rc::ptr_eq(&a, &a);
+
+    let a: Arc<dyn Debug> = Arc::new(1);
+    Arc::ptr_eq(&a, &a);
+
+    // These should be fine:
+    let a = &1;
+    ptr::eq(a, a);
+
+    let a = Rc::new(1);
+    Rc::ptr_eq(&a, &a);
+
+    let a = Arc::new(1);
+    Arc::ptr_eq(&a, &a);
+
+    let a: &[u8] = b"";
+    ptr::eq(a, a);
+}
diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
new file mode 100644
index 00000000000..76bd57217d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
@@ -0,0 +1,83 @@
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:12:13
+   |
+LL |     let _ = a == b;
+   |             ^^^^^^
+   |
+   = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings`
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:13:13
+   |
+LL |     let _ = a != b;
+   |             ^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:14:13
+   |
+LL |     let _ = a < b;
+   |             ^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:15:13
+   |
+LL |     let _ = a <= b;
+   |             ^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:16:13
+   |
+LL |     let _ = a > b;
+   |             ^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:17:13
+   |
+LL |     let _ = a >= b;
+   |             ^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:18:5
+   |
+LL |     ptr::eq(a, b);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:22:5
+   |
+LL |     ptr::eq(a, b);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:25:5
+   |
+LL |     Rc::ptr_eq(&a, &a);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: comparing trait object pointers compares a non-unique vtable address
+  --> $DIR/vtable_address_comparisons.rs:28:5
+   |
+LL |     Arc::ptr_eq(&a, &a);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider extracting and comparing data pointers only
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs
new file mode 100644
index 00000000000..3ce699f551b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_let_loop.rs
@@ -0,0 +1,119 @@
+#![warn(clippy::while_let_loop)]
+
+fn main() {
+    let y = Some(true);
+    loop {
+        if let Some(_x) = y {
+            let _v = 1;
+        } else {
+            break;
+        }
+    }
+
+    #[allow(clippy::never_loop)]
+    loop {
+        // no error, break is not in else clause
+        if let Some(_x) = y {
+            let _v = 1;
+        }
+        break;
+    }
+
+    loop {
+        match y {
+            Some(_x) => true,
+            None => break,
+        };
+    }
+
+    loop {
+        let x = match y {
+            Some(x) => x,
+            None => break,
+        };
+        let _x = x;
+        let _str = "foo";
+    }
+
+    loop {
+        let x = match y {
+            Some(x) => x,
+            None => break,
+        };
+        {
+            let _a = "bar";
+        };
+        {
+            let _b = "foobar";
+        }
+    }
+
+    loop {
+        // no error, else branch does something other than break
+        match y {
+            Some(_x) => true,
+            _ => {
+                let _z = 1;
+                break;
+            },
+        };
+    }
+
+    while let Some(x) = y {
+        // no error, obviously
+        println!("{}", x);
+    }
+
+    // #675, this used to have a wrong suggestion
+    loop {
+        let (e, l) = match "".split_whitespace().next() {
+            Some(word) => (word.is_empty(), word.len()),
+            None => break,
+        };
+
+        let _ = (e, l);
+    }
+}
+
+fn issue771() {
+    let mut a = 100;
+    let b = Some(true);
+    loop {
+        if a > 10 {
+            break;
+        }
+
+        match b {
+            Some(_) => a = 0,
+            None => break,
+        }
+    }
+}
+
+fn issue1017() {
+    let r: Result<u32, u32> = Ok(42);
+    let mut len = 1337;
+
+    loop {
+        match r {
+            Err(_) => len = 0,
+            Ok(length) => {
+                len = length;
+                break;
+            },
+        }
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn issue1948() {
+    // should not trigger clippy::while_let_loop lint because break passes an expression
+    let a = Some(10);
+    let b = loop {
+        if let Some(c) = a {
+            break Some(c);
+        } else {
+            break None;
+        }
+    };
+}
diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr
new file mode 100644
index 00000000000..13dd0ee224c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_let_loop.stderr
@@ -0,0 +1,63 @@
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:5:5
+   |
+LL | /     loop {
+LL | |         if let Some(_x) = y {
+LL | |             let _v = 1;
+LL | |         } else {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `while let Some(_x) = y { .. }`
+   |
+   = note: `-D clippy::while-let-loop` implied by `-D warnings`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:22:5
+   |
+LL | /     loop {
+LL | |         match y {
+LL | |             Some(_x) => true,
+LL | |             None => break,
+LL | |         };
+LL | |     }
+   | |_____^ help: try: `while let Some(_x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:29:5
+   |
+LL | /     loop {
+LL | |         let x = match y {
+LL | |             Some(x) => x,
+LL | |             None => break,
+...  |
+LL | |         let _str = "foo";
+LL | |     }
+   | |_____^ help: try: `while let Some(x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:38:5
+   |
+LL | /     loop {
+LL | |         let x = match y {
+LL | |             Some(x) => x,
+LL | |             None => break,
+...  |
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `while let Some(x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:68:5
+   |
+LL | /     loop {
+LL | |         let (e, l) = match "".split_whitespace().next() {
+LL | |             Some(word) => (word.is_empty(), word.len()),
+LL | |             None => break,
+...  |
+LL | |         let _ = (e, l);
+LL | |     }
+   | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
new file mode 100644
index 00000000000..f5fcabf63fd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -0,0 +1,160 @@
+// run-rustfix
+
+#![warn(clippy::while_let_on_iterator)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+
+fn base() {
+    let mut iter = 1..20;
+    for x in iter {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    for x in iter {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    for _ in iter {}
+
+    let mut iter = 1..20;
+    while let None = iter.next() {} // this is fine (if nonsensical)
+
+    let mut iter = 1..20;
+    if let Some(x) = iter.next() {
+        // also fine
+        println!("{}", x)
+    }
+
+    // the following shouldn't warn because it can't be written with a for loop
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        println!("next: {:?}", iter.next())
+    }
+
+    // neither can this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        println!("next: {:?}", iter.next());
+    }
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        break;
+    }
+    println!("Remaining iter {:?}", iter);
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        iter = 1..20;
+    }
+}
+
+// Issue #1188
+fn refutable() {
+    let a = [42, 1337];
+    let mut b = a.iter();
+
+    // consume all the 42s
+    while let Some(&42) = b.next() {}
+
+    let a = [(1, 2, 3)];
+    let mut b = a.iter();
+
+    while let Some(&(1, 2, 3)) = b.next() {}
+
+    let a = [Some(42)];
+    let mut b = a.iter();
+
+    while let Some(&None) = b.next() {}
+
+    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
+    for &42 in b {}
+    for &(1, 2, 3) in b {}
+    for &Option::None in b.next() {}
+    // */
+}
+
+fn nested_loops() {
+    let a = [42, 1337];
+    let mut y = a.iter();
+    loop {
+        // x is reused, so don't lint here
+        while let Some(_) = y.next() {}
+    }
+
+    let mut y = a.iter();
+    for _ in 0..2 {
+        while let Some(_) = y.next() {
+            // y is reused, don't lint
+        }
+    }
+
+    loop {
+        let mut y = a.iter();
+        for _ in y {
+            // use a for loop here
+        }
+    }
+}
+
+fn issue1121() {
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(&value) = values.iter().next() {
+        values.remove(&value);
+    }
+}
+
+fn issue2965() {
+    // This should not cause an ICE and suggest:
+    //
+    // for _ in values.iter() {}
+    //
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(..) = values.iter().next() {}
+}
+
+fn issue3670() {
+    let array = [Some(0), None, Some(1)];
+    let mut iter = array.iter();
+
+    while let Some(elem) = iter.next() {
+        let _ = elem.or_else(|| *iter.next()?);
+    }
+}
+
+fn issue1654() {
+    // should not lint if the iterator is generated on every iteration
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(..) = values.iter().next() {
+        values.remove(&1);
+    }
+
+    while let Some(..) = values.iter().map(|x| x + 1).next() {}
+
+    let chars = "Hello, World!".char_indices();
+    while let Some((i, ch)) = chars.clone().next() {
+        println!("{}: {}", i, ch);
+    }
+}
+
+fn main() {
+    base();
+    refutable();
+    nested_loops();
+    issue1121();
+    issue2965();
+    issue3670();
+    issue1654();
+}
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
new file mode 100644
index 00000000000..04dce8a0289
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -0,0 +1,160 @@
+// run-rustfix
+
+#![warn(clippy::while_let_on_iterator)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+
+fn base() {
+    let mut iter = 1..20;
+    while let Option::Some(x) = iter.next() {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    while let Some(x) = iter.next() {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    while let Some(_) = iter.next() {}
+
+    let mut iter = 1..20;
+    while let None = iter.next() {} // this is fine (if nonsensical)
+
+    let mut iter = 1..20;
+    if let Some(x) = iter.next() {
+        // also fine
+        println!("{}", x)
+    }
+
+    // the following shouldn't warn because it can't be written with a for loop
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        println!("next: {:?}", iter.next())
+    }
+
+    // neither can this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        println!("next: {:?}", iter.next());
+    }
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        break;
+    }
+    println!("Remaining iter {:?}", iter);
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(_) = iter.next() {
+        iter = 1..20;
+    }
+}
+
+// Issue #1188
+fn refutable() {
+    let a = [42, 1337];
+    let mut b = a.iter();
+
+    // consume all the 42s
+    while let Some(&42) = b.next() {}
+
+    let a = [(1, 2, 3)];
+    let mut b = a.iter();
+
+    while let Some(&(1, 2, 3)) = b.next() {}
+
+    let a = [Some(42)];
+    let mut b = a.iter();
+
+    while let Some(&None) = b.next() {}
+
+    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
+    for &42 in b {}
+    for &(1, 2, 3) in b {}
+    for &Option::None in b.next() {}
+    // */
+}
+
+fn nested_loops() {
+    let a = [42, 1337];
+    let mut y = a.iter();
+    loop {
+        // x is reused, so don't lint here
+        while let Some(_) = y.next() {}
+    }
+
+    let mut y = a.iter();
+    for _ in 0..2 {
+        while let Some(_) = y.next() {
+            // y is reused, don't lint
+        }
+    }
+
+    loop {
+        let mut y = a.iter();
+        while let Some(_) = y.next() {
+            // use a for loop here
+        }
+    }
+}
+
+fn issue1121() {
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(&value) = values.iter().next() {
+        values.remove(&value);
+    }
+}
+
+fn issue2965() {
+    // This should not cause an ICE and suggest:
+    //
+    // for _ in values.iter() {}
+    //
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(..) = values.iter().next() {}
+}
+
+fn issue3670() {
+    let array = [Some(0), None, Some(1)];
+    let mut iter = array.iter();
+
+    while let Some(elem) = iter.next() {
+        let _ = elem.or_else(|| *iter.next()?);
+    }
+}
+
+fn issue1654() {
+    // should not lint if the iterator is generated on every iteration
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(..) = values.iter().next() {
+        values.remove(&1);
+    }
+
+    while let Some(..) = values.iter().map(|x| x + 1).next() {}
+
+    let chars = "Hello, World!".char_indices();
+    while let Some((i, ch)) = chars.clone().next() {
+        println!("{}: {}", i, ch);
+    }
+}
+
+fn main() {
+    base();
+    refutable();
+    nested_loops();
+    issue1121();
+    issue2965();
+    issue3670();
+    issue1654();
+}
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
new file mode 100644
index 00000000000..6de138d7227
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -0,0 +1,28 @@
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:8:5
+   |
+LL |     while let Option::Some(x) = iter.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
+   |
+   = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:13:5
+   |
+LL |     while let Some(x) = iter.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:18:5
+   |
+LL |     while let Some(_) = iter.next() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:97:9
+   |
+LL |         while let Some(_) = y.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.rs b/src/tools/clippy/tests/ui/wild_in_or_pats.rs
new file mode 100644
index 00000000000..ad600f12577
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wild_in_or_pats.rs
@@ -0,0 +1,36 @@
+#![warn(clippy::wildcard_in_or_patterns)]
+
+fn main() {
+    match "foo" {
+        "a" => {
+            dbg!("matched a");
+        },
+        "bar" | _ => {
+            dbg!("matched (bar or) wild");
+        },
+    };
+    match "foo" {
+        "a" => {
+            dbg!("matched a");
+        },
+        "bar" | "bar2" | _ => {
+            dbg!("matched (bar or bar2 or) wild");
+        },
+    };
+    match "foo" {
+        "a" => {
+            dbg!("matched a");
+        },
+        _ | "bar" | _ => {
+            dbg!("matched (bar or) wild");
+        },
+    };
+    match "foo" {
+        "a" => {
+            dbg!("matched a");
+        },
+        _ | "bar" => {
+            dbg!("matched (bar or) wild");
+        },
+    };
+}
diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
new file mode 100644
index 00000000000..33c34cbbd40
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
@@ -0,0 +1,35 @@
+error: wildcard pattern covers any other pattern as it will match anyway.
+  --> $DIR/wild_in_or_pats.rs:8:9
+   |
+LL |         "bar" | _ => {
+   |         ^^^^^^^^^
+   |
+   = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings`
+   = help: Consider handling `_` separately.
+
+error: wildcard pattern covers any other pattern as it will match anyway.
+  --> $DIR/wild_in_or_pats.rs:16:9
+   |
+LL |         "bar" | "bar2" | _ => {
+   |         ^^^^^^^^^^^^^^^^^^
+   |
+   = help: Consider handling `_` separately.
+
+error: wildcard pattern covers any other pattern as it will match anyway.
+  --> $DIR/wild_in_or_pats.rs:24:9
+   |
+LL |         _ | "bar" | _ => {
+   |         ^^^^^^^^^^^^^
+   |
+   = help: Consider handling `_` separately.
+
+error: wildcard pattern covers any other pattern as it will match anyway.
+  --> $DIR/wild_in_or_pats.rs:32:9
+   |
+LL |         _ | "bar" => {
+   |         ^^^^^^^^^
+   |
+   = help: Consider handling `_` separately.
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
new file mode 100644
index 00000000000..2aa24ea1156
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -0,0 +1,101 @@
+// run-rustfix
+
+#![deny(clippy::wildcard_enum_match_arm)]
+#![allow(
+    unreachable_code,
+    unused_variables,
+    dead_code,
+    clippy::single_match,
+    clippy::wildcard_in_or_patterns
+)]
+
+use std::io::ErrorKind;
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum Color {
+    Red,
+    Green,
+    Blue,
+    Rgb(u8, u8, u8),
+    Cyan,
+}
+
+impl Color {
+    fn is_monochrome(self) -> bool {
+        match self {
+            Color::Red | Color::Green | Color::Blue => true,
+            Color::Rgb(r, g, b) => r | g == 0 || r | b == 0 || g | b == 0,
+            Color::Cyan => false,
+        }
+    }
+}
+
+fn main() {
+    let color = Color::Rgb(0, 0, 127);
+    match color {
+        Color::Red => println!("Red"),
+        Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan => eprintln!("Not red"),
+    };
+    match color {
+        Color::Red => println!("Red"),
+        _not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan => eprintln!("Not red"),
+    };
+    let _str = match color {
+        Color::Red => "Red".to_owned(),
+        not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan => format!("{:?}", not_red),
+    };
+    match color {
+        Color::Red => {},
+        Color::Green => {},
+        Color::Blue => {},
+        Color::Cyan => {},
+        c if c.is_monochrome() => {},
+        Color::Rgb(_, _, _) => {},
+    };
+    let _str = match color {
+        Color::Red => "Red",
+        c @ Color::Green | c @ Color::Blue | c @ Color::Rgb(_, _, _) | c @ Color::Cyan => "Not red",
+    };
+    match color {
+        Color::Rgb(r, _, _) if r > 0 => "Some red",
+        Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan => "No red",
+    };
+    match color {
+        Color::Red | Color::Green | Color::Blue | Color::Cyan => {},
+        Color::Rgb(..) => {},
+    };
+    let x: u8 = unimplemented!();
+    match x {
+        0 => {},
+        140 => {},
+        _ => {},
+    };
+    // We need to use an enum not defined in this test because non_exhaustive is ignored for the
+    // purposes of dead code analysis within a crate.
+    let error_kind = ErrorKind::NotFound;
+    match error_kind {
+        ErrorKind::NotFound => {},
+        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 | _ => {},
+    }
+    match error_kind {
+        ErrorKind::NotFound => {},
+        ErrorKind::PermissionDenied => {},
+        ErrorKind::ConnectionRefused => {},
+        ErrorKind::ConnectionReset => {},
+        ErrorKind::ConnectionAborted => {},
+        ErrorKind::NotConnected => {},
+        ErrorKind::AddrInUse => {},
+        ErrorKind::AddrNotAvailable => {},
+        ErrorKind::BrokenPipe => {},
+        ErrorKind::AlreadyExists => {},
+        ErrorKind::WouldBlock => {},
+        ErrorKind::InvalidInput => {},
+        ErrorKind::InvalidData => {},
+        ErrorKind::TimedOut => {},
+        ErrorKind::WriteZero => {},
+        ErrorKind::Interrupted => {},
+        ErrorKind::Other => {},
+        ErrorKind::UnexpectedEof => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
new file mode 100644
index 00000000000..07c93feaf28
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -0,0 +1,101 @@
+// run-rustfix
+
+#![deny(clippy::wildcard_enum_match_arm)]
+#![allow(
+    unreachable_code,
+    unused_variables,
+    dead_code,
+    clippy::single_match,
+    clippy::wildcard_in_or_patterns
+)]
+
+use std::io::ErrorKind;
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum Color {
+    Red,
+    Green,
+    Blue,
+    Rgb(u8, u8, u8),
+    Cyan,
+}
+
+impl Color {
+    fn is_monochrome(self) -> bool {
+        match self {
+            Color::Red | Color::Green | Color::Blue => true,
+            Color::Rgb(r, g, b) => r | g == 0 || r | b == 0 || g | b == 0,
+            Color::Cyan => false,
+        }
+    }
+}
+
+fn main() {
+    let color = Color::Rgb(0, 0, 127);
+    match color {
+        Color::Red => println!("Red"),
+        _ => eprintln!("Not red"),
+    };
+    match color {
+        Color::Red => println!("Red"),
+        _not_red => eprintln!("Not red"),
+    };
+    let _str = match color {
+        Color::Red => "Red".to_owned(),
+        not_red => format!("{:?}", not_red),
+    };
+    match color {
+        Color::Red => {},
+        Color::Green => {},
+        Color::Blue => {},
+        Color::Cyan => {},
+        c if c.is_monochrome() => {},
+        Color::Rgb(_, _, _) => {},
+    };
+    let _str = match color {
+        Color::Red => "Red",
+        c @ Color::Green | c @ Color::Blue | c @ Color::Rgb(_, _, _) | c @ Color::Cyan => "Not red",
+    };
+    match color {
+        Color::Rgb(r, _, _) if r > 0 => "Some red",
+        _ => "No red",
+    };
+    match color {
+        Color::Red | Color::Green | Color::Blue | Color::Cyan => {},
+        Color::Rgb(..) => {},
+    };
+    let x: u8 = unimplemented!();
+    match x {
+        0 => {},
+        140 => {},
+        _ => {},
+    };
+    // We need to use an enum not defined in this test because non_exhaustive is ignored for the
+    // purposes of dead code analysis within a crate.
+    let error_kind = ErrorKind::NotFound;
+    match error_kind {
+        ErrorKind::NotFound => {},
+        _ => {},
+    }
+    match error_kind {
+        ErrorKind::NotFound => {},
+        ErrorKind::PermissionDenied => {},
+        ErrorKind::ConnectionRefused => {},
+        ErrorKind::ConnectionReset => {},
+        ErrorKind::ConnectionAborted => {},
+        ErrorKind::NotConnected => {},
+        ErrorKind::AddrInUse => {},
+        ErrorKind::AddrNotAvailable => {},
+        ErrorKind::BrokenPipe => {},
+        ErrorKind::AlreadyExists => {},
+        ErrorKind::WouldBlock => {},
+        ErrorKind::InvalidInput => {},
+        ErrorKind::InvalidData => {},
+        ErrorKind::TimedOut => {},
+        ErrorKind::WriteZero => {},
+        ErrorKind::Interrupted => {},
+        ErrorKind::Other => {},
+        ErrorKind::UnexpectedEof => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
new file mode 100644
index 00000000000..7151a5c5770
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -0,0 +1,38 @@
+error: wildcard match will miss any future added variants
+  --> $DIR/wildcard_enum_match_arm.rs:37:9
+   |
+LL |         _ => eprintln!("Not red"),
+   |         ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
+   |
+note: the lint level is defined here
+  --> $DIR/wildcard_enum_match_arm.rs:3:9
+   |
+LL | #![deny(clippy::wildcard_enum_match_arm)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: wildcard match will miss any future added variants
+  --> $DIR/wildcard_enum_match_arm.rs:41: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
+   |
+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
+   |
+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
+   |
+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 | _`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
new file mode 100644
index 00000000000..ed6cc00ef04
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -0,0 +1,157 @@
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+//#![allow(clippy::redundant_pub_crate)]
+#![allow(unused)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+#[macro_use]
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import;
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
new file mode 100644
index 00000000000..c6d6efaece8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -0,0 +1,158 @@
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+//#![allow(clippy::redundant_pub_crate)]
+#![allow(unused)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::*;
+use crate::mod_mod::*;
+use crate::multi_fn_mod::*;
+#[macro_use]
+use crate::struct_mod::*;
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import;
+use wildcard_imports_helper::inner::inner_for_self_import::*;
+use wildcard_imports_helper::*;
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::*;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+        use wildcard_imports_helper::*;
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::*, inner2::*};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::*;
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::*;
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::  * ;
+    use crate:: fn_mod::
+        *;
+
+    exported();
+    foo();
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
new file mode 100644
index 00000000000..050e4c6304f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -0,0 +1,96 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:11:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:12:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:13:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:15:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:20:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:89:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:95:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:96:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:107:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:107:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:114:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:143:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:152:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:153:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
new file mode 100644
index 00000000000..d8205c5eb67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -0,0 +1,43 @@
+#![allow(unused_must_use)]
+#![warn(clippy::write_literal)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+
+    // these should be fine
+    write!(&mut v, "Hello");
+    writeln!(&mut v, "Hello");
+    let world = "world";
+    writeln!(&mut v, "Hello {}", world);
+    writeln!(&mut v, "Hello {world}", world = world);
+    writeln!(&mut v, "3 in hex is {:X}", 3);
+    writeln!(&mut v, "2 + 1 = {:.4}", 3);
+    writeln!(&mut v, "2 + 1 = {:5.4}", 3);
+    writeln!(&mut v, "Debug test {:?}", "hello, world");
+    writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
+    writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
+    writeln!(&mut v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{number:>width$}", number = 1, width = 6);
+    writeln!(&mut v, "{number:>0width$}", number = 1, width = 6);
+
+    // these should throw warnings
+    writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
+    write!(&mut v, "Hello {}", "world");
+    writeln!(&mut v, "Hello {} {}", world, "world");
+    writeln!(&mut v, "Hello {}", "world");
+    writeln!(&mut v, "10 / 4 is {}", 2.5);
+    writeln!(&mut v, "2 + 1 = {}", 3);
+
+    // positional args don't change the fact
+    // that we're using a literal -- this should
+    // throw a warning
+    writeln!(&mut v, "{0} {1}", "hello", "world");
+    writeln!(&mut v, "{1} {0}", "hello", "world");
+
+    // named args shouldn't change anything either
+    writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
new file mode 100644
index 00000000000..54a787fe555
--- /dev/null
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -0,0 +1,88 @@
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:27:79
+   |
+LL |     writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
+   |                                                                               ^
+   |
+   = note: `-D clippy::write-literal` implied by `-D warnings`
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:28:32
+   |
+LL |     write!(&mut v, "Hello {}", "world");
+   |                                ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:29:44
+   |
+LL |     writeln!(&mut v, "Hello {} {}", world, "world");
+   |                                            ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:30:34
+   |
+LL |     writeln!(&mut v, "Hello {}", "world");
+   |                                  ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:31:38
+   |
+LL |     writeln!(&mut v, "10 / 4 is {}", 2.5);
+   |                                      ^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:32:36
+   |
+LL |     writeln!(&mut v, "2 + 1 = {}", 3);
+   |                                    ^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:37:33
+   |
+LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
+   |                                 ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:37:42
+   |
+LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
+   |                                          ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:38:33
+   |
+LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
+   |                                 ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:38:42
+   |
+LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
+   |                                          ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:41:43
+   |
+LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                           ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:41:58
+   |
+LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                                          ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:42:43
+   |
+LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                           ^^^^^^^
+
+error: literal with an empty format string
+  --> $DIR/write_literal.rs:42:58
+   |
+LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                                          ^^^^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs
new file mode 100644
index 00000000000..93afd73d111
--- /dev/null
+++ b/src/tools/clippy/tests/ui/write_with_newline.rs
@@ -0,0 +1,58 @@
+// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
+// // run-rustfix
+
+#![allow(clippy::write_literal)]
+#![warn(clippy::write_with_newline)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+
+    // These should fail
+    write!(&mut v, "Hello\n");
+    write!(&mut v, "Hello {}\n", "world");
+    write!(&mut v, "Hello {} {}\n", "world", "#2");
+    write!(&mut v, "{}\n", 1265);
+
+    // These should be fine
+    write!(&mut v, "");
+    write!(&mut v, "Hello");
+    writeln!(&mut v, "Hello");
+    writeln!(&mut v, "Hello\n");
+    writeln!(&mut v, "Hello {}\n", "world");
+    write!(&mut v, "Issue\n{}", 1265);
+    write!(&mut v, "{}", 1265);
+    write!(&mut v, "\n{}", 1275);
+    write!(&mut v, "\n\n");
+    write!(&mut v, "like eof\n\n");
+    write!(&mut v, "Hello {} {}\n\n", "world", "#2");
+    writeln!(&mut v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
+    writeln!(&mut v, "\nbla\n\n"); // #3126
+
+    // Escaping
+    write!(&mut v, "\\n"); // #3514
+    write!(&mut v, "\\\n"); // should fail
+    write!(&mut v, "\\\\n");
+
+    // Raw strings
+    write!(&mut v, r"\n"); // #3778
+
+    // Literal newlines should also fail
+    write!(
+        &mut v,
+        "
+"
+    );
+    write!(
+        &mut v,
+        r"
+"
+    );
+
+    // Don't warn on CRLF (#4208)
+    write!(&mut v, "\r\n");
+    write!(&mut v, "foo\r\n");
+    write!(&mut v, "\\r\n"); //~ ERROR
+    write!(&mut v, "foo\rbar\n");
+}
diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr
new file mode 100644
index 00000000000..2473329ca72
--- /dev/null
+++ b/src/tools/clippy/tests/ui/write_with_newline.stderr
@@ -0,0 +1,114 @@
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:13:5
+   |
+LL |     write!(&mut v, "Hello/n");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::write-with-newline` implied by `-D warnings`
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "Hello");
+   |     ^^^^^^^               --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:14:5
+   |
+LL |     write!(&mut v, "Hello {}/n", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "Hello {}", "world");
+   |     ^^^^^^^                  --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:15:5
+   |
+LL |     write!(&mut v, "Hello {} {}/n", "world", "#2");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "Hello {} {}", "world", "#2");
+   |     ^^^^^^^                     --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:16:5
+   |
+LL |     write!(&mut v, "{}/n", 1265);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "{}", 1265);
+   |     ^^^^^^^            --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:35:5
+   |
+LL |     write!(&mut v, "//n"); // should fail
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "/"); // should fail
+   |     ^^^^^^^            --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:42:5
+   |
+LL | /     write!(
+LL | |         &mut v,
+LL | |         "
+LL | | "
+LL | |     );
+   | |_____^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(
+LL |         &mut v,
+LL |         ""
+   |
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:47:5
+   |
+LL | /     write!(
+LL | |         &mut v,
+LL | |         r"
+LL | | "
+LL | |     );
+   | |_____^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(
+LL |         &mut v,
+LL |         r""
+   |
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:56:5
+   |
+LL |     write!(&mut v, "/r/n"); //~ ERROR
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "/r"); //~ ERROR
+   |     ^^^^^^^             --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:57:5
+   |
+LL |     write!(&mut v, "foo/rbar/n");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, "foo/rbar");
+   |     ^^^^^^^                  --
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.fixed b/src/tools/clippy/tests/ui/writeln_empty_string.fixed
new file mode 100644
index 00000000000..c3ac15b0375
--- /dev/null
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+#![warn(clippy::writeln_empty_string)]
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+
+    // These should fail
+    writeln!(&mut v);
+
+    let mut suggestion = Vec::new();
+    writeln!(&mut suggestion);
+
+    // These should be fine
+    writeln!(&mut v);
+    writeln!(&mut v, " ");
+    write!(&mut v, "");
+}
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.rs b/src/tools/clippy/tests/ui/writeln_empty_string.rs
new file mode 100644
index 00000000000..9a8894b6c0d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+#![warn(clippy::writeln_empty_string)]
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+
+    // These should fail
+    writeln!(&mut v, "");
+
+    let mut suggestion = Vec::new();
+    writeln!(&mut suggestion, "");
+
+    // These should be fine
+    writeln!(&mut v);
+    writeln!(&mut v, " ");
+    write!(&mut v, "");
+}
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
new file mode 100644
index 00000000000..99635229b3e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
@@ -0,0 +1,16 @@
+error: using `writeln!(&mut v, "")`
+  --> $DIR/writeln_empty_string.rs:11:5
+   |
+LL |     writeln!(&mut v, "");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)`
+   |
+   = note: `-D clippy::writeln-empty-string` implied by `-D warnings`
+
+error: using `writeln!(&mut suggestion, "")`
+  --> $DIR/writeln_empty_string.rs:14:5
+   |
+LL |     writeln!(&mut suggestion, "");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs
new file mode 100644
index 00000000000..99652ca4470
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs
@@ -0,0 +1,77 @@
+#![warn(clippy::wrong_self_convention)]
+#![warn(clippy::wrong_pub_self_convention)]
+#![allow(dead_code)]
+
+fn main() {}
+
+#[derive(Clone, Copy)]
+struct Foo;
+
+impl Foo {
+    fn as_i32(self) {}
+    fn as_u32(&self) {}
+    fn into_i32(self) {}
+    fn is_i32(self) {}
+    fn is_u32(&self) {}
+    fn to_i32(self) {}
+    fn from_i32(self) {}
+
+    pub fn as_i64(self) {}
+    pub fn into_i64(self) {}
+    pub fn is_i64(self) {}
+    pub fn to_i64(self) {}
+    pub fn from_i64(self) {}
+    // check whether the lint can be allowed at the function level
+    #[allow(clippy::wrong_self_convention)]
+    pub fn from_cake(self) {}
+
+    fn as_x<F: AsRef<Self>>(_: F) {}
+    fn as_y<F: AsRef<Foo>>(_: F) {}
+}
+
+struct Bar;
+
+impl Bar {
+    fn as_i32(self) {}
+    fn as_u32(&self) {}
+    fn into_i32(&self) {}
+    fn into_u32(self) {}
+    fn is_i32(self) {}
+    fn is_u32(&self) {}
+    fn to_i32(self) {}
+    fn to_u32(&self) {}
+    fn from_i32(self) {}
+
+    pub fn as_i64(self) {}
+    pub fn into_i64(&self) {}
+    pub fn is_i64(self) {}
+    pub fn to_i64(self) {}
+    pub fn from_i64(self) {}
+
+    // test for false positives
+    fn as_(self) {}
+    fn into_(&self) {}
+    fn is_(self) {}
+    fn to_(self) {}
+    fn from_(self) {}
+    fn to_mut(&mut self) {}
+}
+
+// Allow Box<Self>, Rc<Self>, Arc<Self> for methods that take conventionally take Self by value
+#[allow(clippy::boxed_local)]
+mod issue4293 {
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    struct T;
+
+    impl T {
+        fn into_s1(self: Box<Self>) {}
+        fn into_s2(self: Rc<Self>) {}
+        fn into_s3(self: Arc<Self>) {}
+
+        fn into_t1(self: Box<T>) {}
+        fn into_t2(self: Rc<T>) {}
+        fn into_t3(self: Arc<T>) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
new file mode 100644
index 00000000000..0d0eb19cd07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -0,0 +1,76 @@
+error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:17:17
+   |
+LL |     fn from_i32(self) {}
+   |                 ^^^^
+   |
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
+
+error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:23:21
+   |
+LL |     pub fn from_i64(self) {}
+   |                     ^^^^
+
+error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:35:15
+   |
+LL |     fn as_i32(self) {}
+   |               ^^^^
+
+error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:37:17
+   |
+LL |     fn into_i32(&self) {}
+   |                 ^^^^^
+
+error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:39:15
+   |
+LL |     fn is_i32(self) {}
+   |               ^^^^
+
+error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:41:15
+   |
+LL |     fn to_i32(self) {}
+   |               ^^^^
+
+error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:43:17
+   |
+LL |     fn from_i32(self) {}
+   |                 ^^^^
+
+error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:45:19
+   |
+LL |     pub fn as_i64(self) {}
+   |                   ^^^^
+
+error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:46:21
+   |
+LL |     pub fn into_i64(&self) {}
+   |                     ^^^^^
+
+error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:47:19
+   |
+LL |     pub fn is_i64(self) {}
+   |                   ^^^^
+
+error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:48:19
+   |
+LL |     pub fn to_i64(self) {}
+   |                   ^^^^
+
+error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
+  --> $DIR/wrong_self_convention.rs:49:21
+   |
+LL |     pub fn from_i64(self) {}
+   |                     ^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/zero_div_zero.rs b/src/tools/clippy/tests/ui/zero_div_zero.rs
new file mode 100644
index 00000000000..09db130a764
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_div_zero.rs
@@ -0,0 +1,13 @@
+#[allow(unused_variables)]
+#[warn(clippy::zero_divided_by_zero)]
+fn main() {
+    let nan = 0.0 / 0.0;
+    let f64_nan = 0.0 / 0.0f64;
+    let other_f64_nan = 0.0f64 / 0.0;
+    let one_more_f64_nan = 0.0f64 / 0.0f64;
+    let zero = 0.0;
+    let other_zero = 0.0;
+    let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants.
+    let not_nan = 2.0 / 0.0; // not an error: 2/0 = inf
+    let also_not_nan = 0.0 / 2.0; // not an error: 0/2 = 0
+}
diff --git a/src/tools/clippy/tests/ui/zero_div_zero.stderr b/src/tools/clippy/tests/ui/zero_div_zero.stderr
new file mode 100644
index 00000000000..d0e88f3c5a5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_div_zero.stderr
@@ -0,0 +1,61 @@
+error: equal expressions as operands to `/`
+  --> $DIR/zero_div_zero.rs:4:15
+   |
+LL |     let nan = 0.0 / 0.0;
+   |               ^^^^^^^^^
+   |
+   = note: `#[deny(clippy::eq_op)]` on by default
+
+error: constant division of `0.0` with `0.0` will always result in NaN
+  --> $DIR/zero_div_zero.rs:4:15
+   |
+LL |     let nan = 0.0 / 0.0;
+   |               ^^^^^^^^^
+   |
+   = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings`
+   = help: Consider using `f64::NAN` if you would like a constant representing NaN
+
+error: equal expressions as operands to `/`
+  --> $DIR/zero_div_zero.rs:5:19
+   |
+LL |     let f64_nan = 0.0 / 0.0f64;
+   |                   ^^^^^^^^^^^^
+
+error: constant division of `0.0` with `0.0` will always result in NaN
+  --> $DIR/zero_div_zero.rs:5:19
+   |
+LL |     let f64_nan = 0.0 / 0.0f64;
+   |                   ^^^^^^^^^^^^
+   |
+   = help: Consider using `f64::NAN` if you would like a constant representing NaN
+
+error: equal expressions as operands to `/`
+  --> $DIR/zero_div_zero.rs:6:25
+   |
+LL |     let other_f64_nan = 0.0f64 / 0.0;
+   |                         ^^^^^^^^^^^^
+
+error: constant division of `0.0` with `0.0` will always result in NaN
+  --> $DIR/zero_div_zero.rs:6:25
+   |
+LL |     let other_f64_nan = 0.0f64 / 0.0;
+   |                         ^^^^^^^^^^^^
+   |
+   = help: Consider using `f64::NAN` if you would like a constant representing NaN
+
+error: equal expressions as operands to `/`
+  --> $DIR/zero_div_zero.rs:7:28
+   |
+LL |     let one_more_f64_nan = 0.0f64 / 0.0f64;
+   |                            ^^^^^^^^^^^^^^^
+
+error: constant division of `0.0` with `0.0` will always result in NaN
+  --> $DIR/zero_div_zero.rs:7:28
+   |
+LL |     let one_more_f64_nan = 0.0f64 / 0.0f64;
+   |                            ^^^^^^^^^^^^^^^
+   |
+   = help: Consider using `f64::NAN` if you would like a constant representing NaN
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/zero_offset.rs b/src/tools/clippy/tests/ui/zero_offset.rs
new file mode 100644
index 00000000000..2de904376ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_offset.rs
@@ -0,0 +1,12 @@
+fn main() {
+    unsafe {
+        let x = &() as *const ();
+        x.offset(0);
+        x.wrapping_add(0);
+        x.sub(0);
+        x.wrapping_sub(0);
+
+        let y = &1 as *const u8;
+        y.offset(0);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/zero_offset.stderr b/src/tools/clippy/tests/ui/zero_offset.stderr
new file mode 100644
index 00000000000..cfcd7de2b3d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_offset.stderr
@@ -0,0 +1,9 @@
+error[E0606]: casting `&i32` as `*const u8` is invalid
+  --> $DIR/zero_offset.rs:9:17
+   |
+LL |         let y = &1 as *const u8;
+   |                 ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/src/tools/clippy/tests/ui/zero_ptr.fixed b/src/tools/clippy/tests/ui/zero_ptr.fixed
new file mode 100644
index 00000000000..489aa4121a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+pub fn foo(_const: *const f32, _mut: *mut i64) {}
+
+fn main() {
+    let _ = std::ptr::null::<usize>();
+    let _ = std::ptr::null_mut::<f64>();
+    let _: *const u8 = std::ptr::null();
+
+    foo(0 as _, 0 as _);
+    foo(std::ptr::null(), std::ptr::null_mut());
+
+    let z = 0;
+    let _ = z as *const usize; // this is currently not caught
+}
diff --git a/src/tools/clippy/tests/ui/zero_ptr.rs b/src/tools/clippy/tests/ui/zero_ptr.rs
new file mode 100644
index 00000000000..c3b55ef9ebd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+pub fn foo(_const: *const f32, _mut: *mut i64) {}
+
+fn main() {
+    let _ = 0 as *const usize;
+    let _ = 0 as *mut f64;
+    let _: *const u8 = 0 as *const _;
+
+    foo(0 as _, 0 as _);
+    foo(0 as *const _, 0 as *mut _);
+
+    let z = 0;
+    let _ = z as *const usize; // this is currently not caught
+}
diff --git a/src/tools/clippy/tests/ui/zero_ptr.stderr b/src/tools/clippy/tests/ui/zero_ptr.stderr
new file mode 100644
index 00000000000..4ee5e9a2616
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr.stderr
@@ -0,0 +1,34 @@
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr.rs:5:13
+   |
+LL |     let _ = 0 as *const usize;
+   |             ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::null::<usize>()`
+   |
+   = note: `-D clippy::zero-ptr` implied by `-D warnings`
+
+error: `0 as *mut _` detected
+  --> $DIR/zero_ptr.rs:6:13
+   |
+LL |     let _ = 0 as *mut f64;
+   |             ^^^^^^^^^^^^^ help: try: `std::ptr::null_mut::<f64>()`
+
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr.rs:7:24
+   |
+LL |     let _: *const u8 = 0 as *const _;
+   |                        ^^^^^^^^^^^^^ help: try: `std::ptr::null()`
+
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr.rs:10:9
+   |
+LL |     foo(0 as *const _, 0 as *mut _);
+   |         ^^^^^^^^^^^^^ help: try: `std::ptr::null()`
+
+error: `0 as *mut _` detected
+  --> $DIR/zero_ptr.rs:10:24
+   |
+LL |     foo(0 as *const _, 0 as *mut _);
+   |                        ^^^^^^^^^^^ help: try: `std::ptr::null_mut()`
+
+error: aborting due to 5 previous errors
+