about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock6
-rw-r--r--src/tools/clippy/CHANGELOG.md3
-rw-r--r--src/tools/clippy/COPYRIGHT2
-rw-r--r--src/tools/clippy/Cargo.toml3
-rw-r--r--src/tools/clippy/LICENSE-APACHE2
-rw-r--r--src/tools/clippy/LICENSE-MIT2
-rw-r--r--src/tools/clippy/README.md3
-rw-r--r--src/tools/clippy/build.rs2
-rw-r--r--src/tools/clippy/clippy.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/bit_mask.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/double_comparison.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/duration_subsec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/erasing_op.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/eval_order_dependence.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/identity_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs635
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_discriminant.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs219
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmuting_null.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs267
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs84
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs43
-rw-r--r--src/tools/clippy/doc/release.md2
-rw-r--r--src/tools/clippy/mini-macro/Cargo.toml14
-rw-r--r--src/tools/clippy/mini-macro/src/lib.rs29
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs12
-rw-r--r--src/tools/clippy/tests/clippy.toml1
-rw-r--r--src/tools/clippy/tests/compile-test.rs42
-rw-r--r--src/tools/clippy/tests/dogfood.rs31
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs19
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7272.rs12
-rw-r--r--src/tools/clippy/tests/ui/crashes/procedural_macro.rs11
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr14
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs7
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.stderr37
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed3
-rw-r--r--src/tools/clippy/tests/ui/eta.rs3
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr16
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed14
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs14
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr40
-rw-r--r--src/tools/clippy/tests/ui/functions.stderr18
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.fixed3
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.rs3
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.stderr14
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.fixed66
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.rs66
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.stderr64
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.rs5
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.stderr8
-rw-r--r--src/tools/clippy/tests/ui/module_name_repetitions.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed17
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs17
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr16
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow_pat.rs151
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow_pat.stderr112
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.rs8
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs3
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.rs76
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.stderr88
-rw-r--r--src/tools/clippy/tests/ui/similar_names.rs4
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr4
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.rs20
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.stderr75
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.rs2
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.rs3
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr18
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.rs1
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.stderr48
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.rs1
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.stderr4
-rwxr-xr-xsrc/tools/clippy/util/cov.sh37
190 files changed, 2368 insertions, 1310 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b4f23721c7c..75dd899cf5c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -552,10 +552,10 @@ name = "clippy"
 version = "0.1.54"
 dependencies = [
  "cargo_metadata 0.12.0",
- "clippy-mini-macro-test",
  "clippy_lints",
  "compiletest_rs",
  "derive-new",
+ "filetime",
  "quote",
  "regex",
  "rustc-workspace-hack",
@@ -568,10 +568,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-
-[[package]]
 name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index da5a0712c95..41af8e190dd 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -2493,6 +2493,7 @@ Released 2018-09-13
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
@@ -2622,6 +2623,7 @@ Released 2018-09-13
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
@@ -2670,6 +2672,7 @@ Released 2018-09-13
 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
+[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT
index 80d64472c70..238c919b69d 100644
--- a/src/tools/clippy/COPYRIGHT
+++ b/src/tools/clippy/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 848476a9d05..b003b15a11d 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -33,12 +33,13 @@ tempfile = { version = "3.1.0", optional = true }
 cargo_metadata = "0.12"
 compiletest_rs = { version = "0.6.0", features = ["tmp"] }
 tester = "0.9"
-clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
 serde = { version = "1.0", features = ["derive"] }
 derive-new = "0.5"
 regex = "1.4"
 quote = "1"
 syn = { version = "1", features = ["full"] }
+# This is used by the `collect-metadata` alias.
+filetime = "0.2"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE
index d821a4de2be..04169a42b8b 100644
--- a/src/tools/clippy/LICENSE-APACHE
+++ b/src/tools/clippy/LICENSE-APACHE
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT
index b7c70dd4026..90a2d3950d1 100644
--- a/src/tools/clippy/LICENSE-MIT
+++ b/src/tools/clippy/LICENSE-MIT
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2020 The Rust Project Developers
+Copyright (c) 2014-2021 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 8c0c16c443d..6c556f579ca 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -147,6 +147,7 @@ Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml
 value` mapping eg.
 
 ```toml
+avoid-breaking-exported-api = false
 blacklisted-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
@@ -236,7 +237,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 ## License
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
diff --git a/src/tools/clippy/build.rs b/src/tools/clippy/build.rs
index 018375dbada..b5484bec3c8 100644
--- a/src/tools/clippy/build.rs
+++ b/src/tools/clippy/build.rs
@@ -14,6 +14,6 @@ fn main() {
     );
     println!(
         "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
+        rustc_tools_util::get_channel()
     );
 }
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
new file mode 100644
index 00000000000..cda8d17eed4
--- /dev/null
+++ b/src/tools/clippy/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
index 5fbf4bdbd18..49d4350123f 100644
--- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
@@ -3,9 +3,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_isize_or_usize;
diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs
index c560f545d6a..24c2a972811 100644
--- a/src/tools/clippy/clippy_lints/src/arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index c565e29d078..5235b2642d1 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
                 &format!("`assert!(false, {})` should probably be replaced", panic_message),
                 None,
                 &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
-            )
+            );
         };
 
         if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index c5b01461c1c..932cd58bf62 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         if is_relevant_item(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, attrs)
+            check_attrs(cx, item.span, item.ident.name, attrs);
         }
         match item.kind {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
@@ -343,13 +343,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if is_relevant_impl(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if is_relevant_trait(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs
index f7daf3dab49..991ed94572c 100644
--- a/src/tools/clippy/clippy_lints/src/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
@@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
         if let ExprKind::Binary(cmp, left, right) = &e.kind {
             if cmp.node.is_comparison() {
                 if let Some(cmp_opt) = fetch_int_literal(cx, right) {
-                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
+                    check_compare(cx, left, cmp.node, cmp_opt, e.span);
                 } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
-                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
+                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span);
                 }
             }
         }
@@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp
         }
         fetch_int_literal(cx, right)
             .or_else(|| fetch_int_literal(cx, left))
-            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
+            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 67f0e0c7870..e72399af232 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
         _: Span,
         _: HirId,
     ) {
-        NonminimalBoolVisitor { cx }.visit_body(body)
+        NonminimalBoolVisitor { cx }.visit_body(body);
     }
 }
 
@@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
                 Term(n) => {
                     let terminal = self.terminals[n as usize];
                     if let Some(str) = simplify_not(self.cx, terminal) {
-                        self.output.push_str(&str)
+                        self.output.push_str(&str);
                     } else {
                         self.output.push('!');
                         let snip = snippet_opt(self.cx, terminal.span)?;
@@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
         }
         match &e.kind {
             ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
-                self.bool_expr(e)
+                self.bool_expr(e);
             },
             ExprKind::Unary(UnOp::Not, inner) => {
                 if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 040e0ca8864..c9c111a2847 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{method_chain_args, sext};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index dae5c86bd44..6e950738239 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         if !expr.span.from_expansion() {
-            check_if(cx, expr)
+            check_if(cx, expr);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 2a61d58e653..b6999bef6e7 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
             "`if` chain can be rewritten with `match`",
             None,
             "consider rewriting the `if` chain to use `cmp` and `match`",
-        )
+        );
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
deleted file mode 100644
index 7e87f53e3fb..00000000000
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub use clippy_utils::consts::*;
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index f956d171bfb..376a14b8181 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint(
         }
 
         suggestions.push(("end", span, suggestion.to_string()));
-        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit();
     }
 
     let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 6e883942680..759f7d4062d 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -181,9 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
         match stmt.kind {
             StmtKind::Local(local) => {
                 if local.ty.is_some() {
-                    self.ty_bounds.push(TyBound::Any)
+                    self.ty_bounds.push(TyBound::Any);
                 } else {
-                    self.ty_bounds.push(TyBound::Nothing)
+                    self.ty_bounds.push(TyBound::Nothing);
                 }
             },
 
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 50ffc2e3f19..04f3d77464f 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -141,3 +141,22 @@ declare_deprecated_lint! {
     pub FILTER_MAP,
     "this lint has been replaced by `manual_filter_map`, a more specific lint"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `enum_variant_names` lint for public items.
+    /// ```
+    pub PUB_ENUM_VARIANT_NAMES,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items"
+}
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `wrong_self_conversion` lint for public items.
+    pub WRONG_PUB_SELF_CONVENTION,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items"
+}
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 58543ae6e4e..4966638cb1b 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -70,16 +70,16 @@ impl<'tcx> DoubleComparisons {
         #[rustfmt::skip]
         match (op, lkind, rkind) {
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
-                lint_double_comparison!(<=)
+                lint_double_comparison!(<=);
             },
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
-                lint_double_comparison!(>=)
+                lint_double_comparison!(>=);
             },
             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
-                lint_double_comparison!(!=)
+                lint_double_comparison!(!=);
             },
             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
-                lint_double_comparison!(==)
+                lint_double_comparison!(==);
             },
             _ => (),
         };
diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
index 529807770f3..94b09bf7173 100644
--- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
@@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths;
 
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 8db5050a5ac..2eb8b1422ed 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -469,7 +469,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
                     let mut is_map_used = self.is_map_used;
                     for arm in arms {
                         if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
-                            self.visit_non_tail_expr(guard)
+                            self.visit_non_tail_expr(guard);
                         }
                         is_map_used |= self.visit_cond_arm(arm.body);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 7a98ae39d3a..021136ac5e0 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -1,7 +1,7 @@
 //! lint on C-like enums that are `repr(isize/usize)` and have values that
 //! don't fit into an `i32`
 
-use crate::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{miri_to_const, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 0ecc0bc3eb6..b1a105a51c1 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -3,8 +3,8 @@
 use clippy_utils::camel_case;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::is_present_in_source;
-use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_hir::{EnumDef, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -40,36 +40,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Detects public enumeration variants that are
-    /// prefixed or suffixed by the same characters.
-    ///
-    /// **Why is this bad?** Public enumeration variant names should specify their variant,
-    /// not repeat the enumeration name.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForestCake,
-    ///     HummingbirdCake,
-    ///     BattenbergCake,
-    /// }
-    /// ```
-    /// Could be written as:
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForest,
-    ///     Hummingbird,
-    ///     Battenberg,
-    /// }
-    /// ```
-    pub PUB_ENUM_VARIANT_NAMES,
-    pedantic,
-    "public enums where all variants share a prefix/postfix"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Detects type names that are prefixed or suffixed by the
     /// containing module's name.
     ///
@@ -127,21 +97,22 @@ declare_clippy_lint! {
 pub struct EnumVariantNames {
     modules: Vec<(Symbol, String)>,
     threshold: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl EnumVariantNames {
     #[must_use]
-    pub fn new(threshold: u64) -> Self {
+    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
         Self {
             modules: Vec::new(),
             threshold,
+            avoid_breaking_exported_api,
         }
     }
 }
 
 impl_lint_pass!(EnumVariantNames => [
     ENUM_VARIANT_NAMES,
-    PUB_ENUM_VARIANT_NAMES,
     MODULE_NAME_REPETITIONS,
     MODULE_INCEPTION
 ]);
@@ -167,33 +138,42 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
 }
 
 fn check_variant(
-    cx: &EarlyContext<'_>,
+    cx: &LateContext<'_>,
     threshold: u64,
-    def: &EnumDef,
+    def: &EnumDef<'_>,
     item_name: &str,
     item_name_chars: usize,
     span: Span,
-    lint: &'static Lint,
 ) {
     if (def.variants.len() as u64) < threshold {
         return;
     }
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
         if partial_match(item_name, &name) == item_name_chars
             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
         {
-            span_lint(cx, lint, var.span, "variant name starts with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name starts with the enum's name",
+            );
         }
         if partial_rmatch(item_name, &name) == item_name_chars {
-            span_lint(cx, lint, var.span, "variant name ends with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name ends with the enum's name",
+            );
         }
     }
     let first = &def.variants[0].ident.name.as_str();
     let mut pre = &first[..camel_case::until(&*first)];
     let mut post = &first[camel_case::from(&*first)..];
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
 
         let pre_match = partial_match(pre, &name);
@@ -226,7 +206,7 @@ fn check_variant(
     };
     span_lint_and_help(
         cx,
-        lint,
+        ENUM_VARIANT_NAMES,
         span,
         &format!("all variants have the same {}fix: `{}`", what, value),
         None,
@@ -261,14 +241,14 @@ fn to_camel_case(item_name: &str) -> String {
     s
 }
 
-impl EarlyLintPass for EnumVariantNames {
-    fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
+impl LateLintPass<'_> for EnumVariantNames {
+    fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
         let last = self.modules.pop();
         assert!(last.is_some());
     }
 
     #[allow(clippy::similar_names)]
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         let item_name = item.ident.name.as_str();
         let item_name_chars = item_name.chars().count();
         let item_camel = to_camel_case(&item_name);
@@ -286,7 +266,7 @@ impl EarlyLintPass for EnumVariantNames {
                             );
                         }
                     }
-                    if item.vis.kind.is_pub() {
+                    if item.vis.node.is_pub() {
                         let matching = partial_match(mod_camel, &item_camel);
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
@@ -317,11 +297,9 @@ impl EarlyLintPass for EnumVariantNames {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let lint = match item.vis.kind {
-                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
-                _ => ENUM_VARIANT_NAMES,
-            };
-            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
+            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+                check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
+            }
         }
         self.modules.push((item.ident.name, item_camel));
     }
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 90f391b5f5c..a3a8e748d99 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         vec![(left.span, lsnip), (right.span, rsnip)],
                                     );
                                 },
-                            )
+                            );
                         } else if lcpy
                             && !rcpy
                             && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
@@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         } else if !lcpy
                             && rcpy
                             && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
@@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // &foo == bar
@@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // foo == &bar
@@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                     rsnip,
                                     Applicability::MaybeIncorrect, // FIXME #2597
                                 );
-                            })
+                            });
                         }
                     },
                     _ => {},
diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs
index f95ca86a2d0..4aa9c25b1b0 100644
--- a/src/tools/clippy/clippy_lints/src/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs
@@ -1,11 +1,10 @@
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for erasing operations, e.g., `x * 0`.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2f1aa53236d..8d066f305ee 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                 for arg in args {
                     // skip `foo(macro!())`
                     if arg.span.ctxt() == expr.span.ctxt() {
-                        check_closure(cx, arg)
+                        check_closure(cx, arg);
                     }
                 }
             },
@@ -92,17 +92,19 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
         let ex = &body.value;
 
         if ex.span.ctxt() != expr.span.ctxt() {
-            if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
-                // replace `|| vec![]` with `Vec::new`
-                span_lint_and_sugg(
-                    cx,
-                    REDUNDANT_CLOSURE,
-                    expr.span,
-                    "redundant closure",
-                    "replace the closure with `Vec::new`",
-                    "std::vec::Vec::new".into(),
-                    Applicability::MachineApplicable,
-                );
+            if decl.inputs.is_empty() {
+                if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+                    // replace `|| vec![]` with `Vec::new`
+                    span_lint_and_sugg(
+                        cx,
+                        REDUNDANT_CLOSURE,
+                        expr.span,
+                        "redundant closure",
+                        "replace the closure with `Vec::new`",
+                        "std::vec::Vec::new".into(),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
             // skip `foo(|| macro!())`
             return;
@@ -188,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
     cx.tcx.impl_of_method(method_def_id).and_then(|_| {
         //a type may implicitly implement other type's methods (e.g. Deref)
         if match_types(expected_type_of_self, actual_type_of_self) {
-            return Some(get_type_name(cx, actual_type_of_self));
+            Some(get_type_name(cx, actual_type_of_self))
+        } else {
+            None
         }
-        None
     })
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
index 41acf55dd7d..5fdf5bc9e9d 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
@@ -110,7 +110,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
                 self.visit_expr(e);
                 for arm in arms {
                     if let Some(Guard::If(if_expr)) = arm.guard {
-                        self.visit_expr(if_expr)
+                        self.visit_expr(if_expr);
                     }
                     // make sure top level arm expressions aren't linted
                     self.maybe_walk_expr(&*arm.body);
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 08f28cd54c5..e38384b01d4 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::{
+use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 20288427b4a..7f4fb68cf2f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -240,7 +240,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                 }
             },
             Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
-                self.mutates_static |= is_mutated_static(target)
+                self.mutates_static |= is_mutated_static(target);
             },
             _ => {},
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index b8ea6990866..af759a48e10 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
                     self.cx,
                     NOT_UNSAFE_PTR_ARG_DEREF,
                     ptr.span,
-                    "this public function dereferences a raw pointer but is not marked `unsafe`",
+                    "this public function might dereference a raw pointer but is not marked `unsafe`",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index aa5494d5a7d..a666fee1a4a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -4,7 +4,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_opt;
 
 use super::TOO_MANY_LINES;
 
@@ -13,15 +13,25 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
         return;
     }
 
-    let code_snippet = snippet(cx, body.value.span, "..");
+    let code_snippet = match snippet_opt(cx, body.value.span) {
+        Some(s) => s,
+        _ => return,
+    };
     let mut line_count: u64 = 0;
     let mut in_comment = false;
     let mut code_in_line;
 
-    // Skip the surrounding function decl.
-    let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
-    let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
-    let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+    let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
+        && code_snippet.as_bytes().first().copied() == Some(b'{')
+        && code_snippet.as_bytes().last().copied() == Some(b'}')
+    {
+        // Removing the braces from the enclosing block
+        &code_snippet[1..code_snippet.len() - 1]
+    } else {
+        &code_snippet
+    }
+    .trim() // Remove leading and trailing blank lines
+    .lines();
 
     for mut line in function_lines {
         code_in_line = false;
@@ -63,6 +73,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
                 "this function has too many lines ({}/{})",
                 line_count, too_many_lines_threshold
             ),
-        )
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 04730ace887..515b8887453 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                                         ));
                                     }
                                 }
-                            })
+                            });
                         },
                     );
                 }
diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs
index 366b3b46a8a..99c461930e4 100644
--- a/src/tools/clippy/clippy_lints/src/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/identity_op.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{clip, unsext};
 
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 260a8f50157..f2f830ca5c0 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) {
         "change `break` to `return` as shown",
         format!("return {}", snip),
         app,
-    )
+    );
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 1c54599abc4..bfa284f333a 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -1,6 +1,6 @@
 //! lint on indexing and slicing operations
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher;
 use rustc_ast::ast::RangeLimits;
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index afee20ce43e..6b887da2630 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
                 return;
             },
         };
-        span_lint(cx, lint, expr.span, msg)
+        span_lint(cx, lint, expr.span, msg);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index c67c02eefa5..37011f5578d 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -7,9 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 use rustc_target::abi::LayoutOf;
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::Rel;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
 use clippy_utils::{comparisons, sext};
@@ -177,7 +176,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, true)
+                err_upcast_comparison(cx, span, lhs, true);
             } else if match rel {
                 Rel::Lt => {
                     if invert {
@@ -195,7 +194,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, false)
+                err_upcast_comparison(cx, span, lhs, false);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index bb57adff7be..583514b22f9 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
     } else {
-        check_empty_expr(cx, span, method, lit, op)
+        check_empty_expr(cx, span, method, lit, op);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 17e23781db7..e627b1385bc 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if init_ty.needs_drop(cx.tcx, cx.param_env) {
                     span_lint_and_help(
                         cx,
@@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                     span_lint_and_help(
                         cx,
@@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding let on an expression with `#[must_use]` type",
                         None,
                         "consider explicitly using expression value"
-                    )
+                    );
                 } else if is_must_use_func_call(cx, init) {
                     span_lint_and_help(
                         cx,
@@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding let on a result of a `#[must_use]` function",
                         None,
                         "consider explicitly using function result"
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 2c83409b402..e7dd3952b3a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -41,6 +41,9 @@ extern crate rustc_target;
 extern crate rustc_trait_selection;
 extern crate rustc_typeck;
 
+#[macro_use]
+extern crate clippy_utils;
+
 use clippy_utils::parse_msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::LintId;
@@ -145,25 +148,9 @@ macro_rules! declare_clippy_lint {
     };
 }
 
-#[macro_export]
-macro_rules! sym {
-    ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
-}
-
-#[macro_export]
-macro_rules! unwrap_cargo_metadata {
-    ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
-}
-
-macro_rules! extract_msrv_attr {
-    ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
-}
-
-mod consts;
-#[macro_use]
-mod utils;
 #[cfg(feature = "metadata-collector-lint")]
 mod deprecated_lints;
+mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
@@ -405,7 +392,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 
 #[doc(hidden)]
 pub fn read_conf(sess: &Session) -> Conf {
-    use std::path::Path;
     let file_name = match utils::conf::lookup_conf_file() {
         Ok(Some(path)) => path,
         Ok(None) => return Conf::default(),
@@ -416,16 +402,6 @@ pub fn read_conf(sess: &Session) -> Conf {
         },
     };
 
-    let file_name = if file_name.is_relative() {
-        sess.local_crate_source_file
-            .as_deref()
-            .and_then(Path::parent)
-            .unwrap_or_else(|| Path::new(""))
-            .join(file_name)
-    } else {
-        file_name
-    };
-
     let TryConf { conf, errors } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
@@ -505,6 +481,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "clippy::filter_map",
         "this lint has been replaced by `manual_filter_map`, a more specific lint",
     );
+    store.register_removed(
+        "clippy::pub_enum_variant_names",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items",
+    );
+    store.register_removed(
+        "clippy::wrong_pub_self_convention",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -618,7 +602,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         enum_variants::ENUM_VARIANT_NAMES,
         enum_variants::MODULE_INCEPTION,
         enum_variants::MODULE_NAME_REPETITIONS,
-        enum_variants::PUB_ENUM_VARIANT_NAMES,
         eq_op::EQ_OP,
         eq_op::OP_REF,
         erasing_op::ERASING_OP,
@@ -779,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::MANUAL_FILTER_MAP,
         methods::MANUAL_FIND_MAP,
         methods::MANUAL_SATURATING_ARITHMETIC,
+        methods::MANUAL_STR_REPEAT,
         methods::MAP_COLLECT_RESULT_UNIT,
         methods::MAP_FLATTEN,
         methods::MAP_UNWRAP_OR,
@@ -796,13 +780,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::SKIP_WHILE_NEXT,
         methods::STRING_EXTEND_CHARS,
         methods::SUSPICIOUS_MAP,
+        methods::SUSPICIOUS_SPLITN,
         methods::UNINIT_ASSUMED_INIT,
         methods::UNNECESSARY_FILTER_MAP,
         methods::UNNECESSARY_FOLD,
         methods::UNNECESSARY_LAZY_EVALUATIONS,
         methods::UNWRAP_USED,
         methods::USELESS_ASREF,
-        methods::WRONG_PUB_SELF_CONVENTION,
         methods::WRONG_SELF_CONVENTION,
         methods::ZST_OFFSET,
         minmax::MIN_MAX,
@@ -841,6 +825,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
         needless_borrow::NEEDLESS_BORROW,
+        needless_borrow::REF_BINDING_TO_REFERENCE,
         needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
         needless_continue::NEEDLESS_CONTINUE,
         needless_for_each::NEEDLESS_FOR_EACH,
@@ -995,291 +980,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     ]);
     // end register lints, do not remove this comment, it’s used in `update_lints`
 
-    // all the internal lints
-    #[cfg(feature = "internal-lints")]
-    {
-        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
-        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
-        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
-        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
-        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
-        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
-        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
-        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
-        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
-        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
-        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
-    }
-    #[cfg(feature = "metadata-collector-lint")]
-    {
-        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
-        }
-    }
-
-    store.register_late_pass(|| box utils::author::Author);
-    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
-    store.register_late_pass(|| box serde_api::SerdeApi);
-    let vec_box_size_threshold = conf.vec_box_size_threshold;
-    let type_complexity_threshold = conf.type_complexity_threshold;
-    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
-    store.register_late_pass(|| box booleans::NonminimalBool);
-    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
-    store.register_late_pass(|| box eq_op::EqOp);
-    store.register_late_pass(|| box enum_clike::UnportableVariant);
-    store.register_late_pass(|| box float_literal::FloatLiteral);
-    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
-    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
-    store.register_late_pass(|| box ptr::Ptr);
-    store.register_late_pass(|| box ptr_eq::PtrEq);
-    store.register_late_pass(|| box needless_bool::NeedlessBool);
-    store.register_late_pass(|| box needless_bool::BoolComparison);
-    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
-    store.register_late_pass(|| box approx_const::ApproxConstant);
-    store.register_late_pass(|| box misc::MiscLints);
-    store.register_late_pass(|| box eta_reduction::EtaReduction);
-    store.register_late_pass(|| box identity_op::IdentityOp);
-    store.register_late_pass(|| box erasing_op::ErasingOp);
-    store.register_late_pass(|| box mut_mut::MutMut);
-    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
-    store.register_late_pass(|| box len_zero::LenZero);
-    store.register_late_pass(|| box attrs::Attributes);
-    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
-    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
-    store.register_late_pass(|| box unicode::Unicode);
-    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
-    store.register_late_pass(|| box strings::StringAdd);
-    store.register_late_pass(|| box implicit_return::ImplicitReturn);
-    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
-    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
-    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
-    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
-    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
-
-    let msrv = conf.msrv.as_ref().and_then(|s| {
-        parse_msrv(s, None, None).or_else(|| {
-            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
-            None
-        })
-    });
-
-    store.register_late_pass(move || box methods::Methods::new(msrv));
-    store.register_late_pass(move || box matches::Matches::new(msrv));
-    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
-    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
-    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
-    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
-    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
-    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
-    store.register_late_pass(move || box ranges::Ranges::new(msrv));
-    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
-    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
-    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
-    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
-    store.register_late_pass(move || box casts::Casts::new(msrv));
-    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
-
-    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
-    store.register_late_pass(|| box map_clone::MapClone);
-    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
-    store.register_late_pass(|| box shadow::Shadow);
-    store.register_late_pass(|| box unit_types::UnitTypes);
-    store.register_late_pass(|| box loops::Loops);
-    store.register_late_pass(|| box main_recursion::MainRecursion::default());
-    store.register_late_pass(|| box lifetimes::Lifetimes);
-    store.register_late_pass(|| box entry::HashMapPass);
-    store.register_late_pass(|| box minmax::MinMaxPass);
-    store.register_late_pass(|| box open_options::OpenOptions);
-    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
-    store.register_late_pass(|| box mutex_atomic::Mutex);
-    store.register_late_pass(|| box needless_update::NeedlessUpdate);
-    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
-    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
-    store.register_late_pass(|| box no_effect::NoEffect);
-    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
-    store.register_late_pass(|| box transmute::Transmute);
-    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
-    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
-    let too_large_for_stack = conf.too_large_for_stack;
-    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
-    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
-    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
-    store.register_late_pass(|| box strings::StringLitAsBytes);
-    store.register_late_pass(|| box derive::Derive);
-    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
-    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
-    store.register_late_pass(|| box empty_enum::EmptyEnum);
-    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
-    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
-    store.register_late_pass(|| box regex::Regex::default());
-    store.register_late_pass(|| box copies::CopyAndPaste);
-    store.register_late_pass(|| box copy_iterator::CopyIterator);
-    store.register_late_pass(|| box format::UselessFormat);
-    store.register_late_pass(|| box swap::Swap);
-    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
-    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
-    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
-    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
-    let too_many_lines_threshold = conf.too_many_lines_threshold;
-    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
-    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
-    store.register_late_pass(|| box neg_multiply::NegMultiply);
-    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
-    store.register_late_pass(|| box mem_forget::MemForget);
-    store.register_late_pass(|| box arithmetic::Arithmetic::default());
-    store.register_late_pass(|| box assign_ops::AssignOps);
-    store.register_late_pass(|| box let_if_seq::LetIfSeq);
-    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
-    store.register_late_pass(|| box missing_doc::MissingDoc::new());
-    store.register_late_pass(|| box missing_inline::MissingInline);
-    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
-    store.register_late_pass(|| box if_let_some_result::OkIfLet);
-    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
-    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
-    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
-    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
-    store.register_late_pass(|| box explicit_write::ExplicitWrite);
-    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
-    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
-        conf.trivial_copy_size_limit,
-        conf.pass_by_value_size_limit,
-        &sess.target,
-    );
-    store.register_late_pass(move || box pass_by_ref_or_value);
-    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
-    store.register_late_pass(|| box try_err::TryErr);
-    store.register_late_pass(|| box bytecount::ByteCount);
-    store.register_late_pass(|| box infinite_iter::InfiniteIter);
-    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
-    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
-    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
-    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
-    store.register_late_pass(|| box double_comparison::DoubleComparisons);
-    store.register_late_pass(|| box question_mark::QuestionMark);
-    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
-    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
-    store.register_late_pass(|| box map_unit_fn::MapUnit);
-    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
-    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
-    store.register_late_pass(|| box unwrap::Unwrap);
-    store.register_late_pass(|| box duration_subsec::DurationSubsec);
-    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
-    store.register_late_pass(|| box non_copy_const::NonCopyConst);
-    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
-    store.register_late_pass(|| box redundant_clone::RedundantClone);
-    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
-    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
-    store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
-    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
-    store.register_late_pass(|| box transmuting_null::TransmutingNull);
-    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
-    store.register_late_pass(|| box integer_division::IntegerDivision);
-    store.register_late_pass(|| box inherent_to_string::InherentToString);
-    let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
-    store.register_late_pass(|| box comparison_chain::ComparisonChain);
-    store.register_late_pass(|| box mut_key::MutableKeyType);
-    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
-    store.register_early_pass(|| box reference::DerefAddrOf);
-    store.register_early_pass(|| box reference::RefInDeref);
-    store.register_early_pass(|| box double_parens::DoubleParens);
-    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
-    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
-    store.register_early_pass(|| box if_not_else::IfNotElse);
-    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
-    store.register_early_pass(|| box int_plus_one::IntPlusOne);
-    store.register_early_pass(|| box formatting::Formatting);
-    store.register_early_pass(|| box misc_early::MiscEarlyLints);
-    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_early_pass(|| box unused_unit::UnusedUnit);
-    store.register_late_pass(|| box returns::Return);
-    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
-    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
-    store.register_early_pass(|| box precedence::Precedence);
-    store.register_early_pass(|| box needless_continue::NeedlessContinue);
-    store.register_early_pass(|| box redundant_else::RedundantElse);
-    store.register_late_pass(|| box create_dir::CreateDir);
-    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
-    let cargo_ignore_publish = conf.cargo_ignore_publish;
-    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
-    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
-    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
-    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
-    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
-    let literal_representation_threshold = conf.literal_representation_threshold;
-    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
-    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
-    store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
-    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
-    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
-    store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive));
-    store.register_late_pass(|| box default::Default::default());
-    store.register_late_pass(|| box unused_self::UnusedSelf);
-    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
-    store.register_late_pass(|| box exit::Exit);
-    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
-    let array_size_threshold = conf.array_size_threshold;
-    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
-    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
-    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
-    store.register_early_pass(|| box as_conversions::AsConversions);
-    store.register_late_pass(|| box let_underscore::LetUnderscore);
-    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
-    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
-    let max_fn_params_bools = conf.max_fn_params_bools;
-    let max_struct_bools = conf.max_struct_bools;
-    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
-    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
-    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
-    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
-    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
-    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
-    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
-    store.register_late_pass(|| box dereference::Dereferencing::default());
-    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
-    store.register_late_pass(|| box future_not_send::FutureNotSend);
-    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
-    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
-    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
-    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
-    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
-    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
-    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
-    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
-        single_char_binding_names_threshold,
-    });
-    store.register_late_pass(|| box macro_use::MacroUseImports::default());
-    store.register_late_pass(|| box map_identity::MapIdentity);
-    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
-    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
-    store.register_late_pass(|| box repeat_once::RepeatOnce);
-    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
-    store.register_late_pass(|| box self_assignment::SelfAssignment);
-    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
-    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
-    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
-    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
-    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
-    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
-    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
-    store.register_late_pass(|| box strings::StrToString);
-    store.register_late_pass(|| box strings::StringToString);
-    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
-    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
-    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
-    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
-    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
-    store.register_late_pass(|| box manual_map::ManualMap);
-    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
-    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
-    store.register_late_pass(|| box unused_async::UnusedAsync);
-
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(arithmetic::FLOAT_ARITHMETIC),
         LintId::of(arithmetic::INTEGER_ARITHMETIC),
@@ -1310,7 +1010,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::FILETYPE_IS_FILE),
         LintId::of(methods::GET_UNWRAP),
         LintId::of(methods::UNWRAP_USED),
-        LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
         LintId::of(misc::FLOAT_CMP_CONST),
         LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
         LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
@@ -1322,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(panic_unimplemented::UNIMPLEMENTED),
         LintId::of(panic_unimplemented::UNREACHABLE),
         LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
-        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
         LintId::of(shadow::SHADOW_REUSE),
         LintId::of(shadow::SHADOW_SAME),
         LintId::of(strings::STRING_ADD),
@@ -1363,7 +1061,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(doc::MISSING_PANICS_DOC),
         LintId::of(empty_enum::EMPTY_ENUM),
         LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
-        LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
         LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
         LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
         LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
@@ -1401,6 +1098,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
         LintId::of(mut_mut::MUT_MUT),
         LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
+        LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
         LintId::of(needless_continue::NEEDLESS_CONTINUE),
         LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
         LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
@@ -1412,6 +1110,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(ranges::RANGE_PLUS_ONE),
         LintId::of(redundant_else::REDUNDANT_ELSE),
         LintId::of(ref_option_ref::REF_OPTION_REF),
+        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
         LintId::of(shadow::SHADOW_UNRELATED),
         LintId::of(strings::STRING_ADD_ASSIGN),
         LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
@@ -1600,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::MANUAL_FILTER_MAP),
         LintId::of(methods::MANUAL_FIND_MAP),
         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(methods::NEW_RET_NO_SELF),
         LintId::of(methods::OK_EXPECT),
@@ -1615,6 +1315,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::SKIP_WHILE_NEXT),
         LintId::of(methods::STRING_EXTEND_CHARS),
         LintId::of(methods::SUSPICIOUS_MAP),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::UNNECESSARY_FILTER_MAP),
         LintId::of(methods::UNNECESSARY_FOLD),
@@ -1644,6 +1345,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
         LintId::of(needless_bool::BOOL_COMPARISON),
         LintId::of(needless_bool::NEEDLESS_BOOL),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
         LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
         LintId::of(needless_update::NEEDLESS_UPDATE),
@@ -1690,7 +1392,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(swap::ALMOST_SWAPPED),
@@ -1827,6 +1528,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc_early::REDUNDANT_PATTERN),
         LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
         LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(neg_multiply::NEG_MULTIPLY),
         LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
         LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
@@ -1843,7 +1545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(returns::LET_AND_RETURN),
         LintId::of(returns::NEEDLESS_RETURN),
         LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
         LintId::of(try_err::TRY_ERR),
@@ -1991,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
         LintId::of(methods::CLONE_DOUBLE_REF),
         LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::ZST_OFFSET),
         LintId::of(minmax::MIN_MAX),
@@ -2035,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(loops::NEEDLESS_COLLECT),
         LintId::of(methods::EXPECT_FUN_CALL),
         LintId::of(methods::ITER_NTH),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::OR_FUN_CALL),
         LintId::of(methods::SINGLE_CHAR_PATTERN),
         LintId::of(misc::CMP_OWNED),
@@ -2066,14 +1769,304 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
         LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
         LintId::of(mutex_atomic::MUTEX_INTEGER),
-        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
         LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
         LintId::of(regex::TRIVIAL_REGEX),
         LintId::of(strings::STRING_LIT_AS_BYTES),
+        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(transmute::USELESS_TRANSMUTE),
         LintId::of(use_self::USE_SELF),
     ]);
+
+    #[cfg(feature = "metadata-collector-lint")]
+    {
+        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
+            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
+            return;
+        }
+    }
+
+    // all the internal lints
+    #[cfg(feature = "internal-lints")]
+    {
+        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
+        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
+        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
+        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
+        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
+        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
+        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
+        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
+        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
+    }
+
+    store.register_late_pass(|| box utils::author::Author);
+    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
+    store.register_late_pass(|| box serde_api::SerdeApi);
+    let vec_box_size_threshold = conf.vec_box_size_threshold;
+    let type_complexity_threshold = conf.type_complexity_threshold;
+    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
+    store.register_late_pass(|| box booleans::NonminimalBool);
+    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
+    store.register_late_pass(|| box eq_op::EqOp);
+    store.register_late_pass(|| box enum_clike::UnportableVariant);
+    store.register_late_pass(|| box float_literal::FloatLiteral);
+    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
+    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
+    store.register_late_pass(|| box ptr::Ptr);
+    store.register_late_pass(|| box ptr_eq::PtrEq);
+    store.register_late_pass(|| box needless_bool::NeedlessBool);
+    store.register_late_pass(|| box needless_bool::BoolComparison);
+    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
+    store.register_late_pass(|| box approx_const::ApproxConstant);
+    store.register_late_pass(|| box misc::MiscLints);
+    store.register_late_pass(|| box eta_reduction::EtaReduction);
+    store.register_late_pass(|| box identity_op::IdentityOp);
+    store.register_late_pass(|| box erasing_op::ErasingOp);
+    store.register_late_pass(|| box mut_mut::MutMut);
+    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
+    store.register_late_pass(|| box len_zero::LenZero);
+    store.register_late_pass(|| box attrs::Attributes);
+    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
+    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
+    store.register_late_pass(|| box unicode::Unicode);
+    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
+    store.register_late_pass(|| box strings::StringAdd);
+    store.register_late_pass(|| box implicit_return::ImplicitReturn);
+    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
+    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
+    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+
+    let msrv = conf.msrv.as_ref().and_then(|s| {
+        parse_msrv(s, None, None).or_else(|| {
+            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+            None
+        })
+    });
+
+    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+    store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv));
+    store.register_late_pass(move || box matches::Matches::new(msrv));
+    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
+    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+    store.register_late_pass(move || box ranges::Ranges::new(msrv));
+    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
+    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
+    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
+    store.register_late_pass(move || box casts::Casts::new(msrv));
+    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
+
+    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
+    store.register_late_pass(|| box map_clone::MapClone);
+    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
+    store.register_late_pass(|| box shadow::Shadow);
+    store.register_late_pass(|| box unit_types::UnitTypes);
+    store.register_late_pass(|| box loops::Loops);
+    store.register_late_pass(|| box main_recursion::MainRecursion::default());
+    store.register_late_pass(|| box lifetimes::Lifetimes);
+    store.register_late_pass(|| box entry::HashMapPass);
+    store.register_late_pass(|| box minmax::MinMaxPass);
+    store.register_late_pass(|| box open_options::OpenOptions);
+    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
+    store.register_late_pass(|| box mutex_atomic::Mutex);
+    store.register_late_pass(|| box needless_update::NeedlessUpdate);
+    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
+    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
+    store.register_late_pass(|| box no_effect::NoEffect);
+    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
+    store.register_late_pass(|| box transmute::Transmute);
+    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
+    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
+    let too_large_for_stack = conf.too_large_for_stack;
+    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
+    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
+    store.register_late_pass(|| box strings::StringLitAsBytes);
+    store.register_late_pass(|| box derive::Derive);
+    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
+    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
+    store.register_late_pass(|| box empty_enum::EmptyEnum);
+    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
+    store.register_late_pass(|| box regex::Regex::default());
+    store.register_late_pass(|| box copies::CopyAndPaste);
+    store.register_late_pass(|| box copy_iterator::CopyIterator);
+    store.register_late_pass(|| box format::UselessFormat);
+    store.register_late_pass(|| box swap::Swap);
+    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
+    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
+    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
+    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+    let too_many_lines_threshold = conf.too_many_lines_threshold;
+    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
+    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
+    store.register_late_pass(|| box neg_multiply::NegMultiply);
+    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
+    store.register_late_pass(|| box mem_forget::MemForget);
+    store.register_late_pass(|| box arithmetic::Arithmetic::default());
+    store.register_late_pass(|| box assign_ops::AssignOps);
+    store.register_late_pass(|| box let_if_seq::LetIfSeq);
+    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
+    store.register_late_pass(|| box missing_doc::MissingDoc::new());
+    store.register_late_pass(|| box missing_inline::MissingInline);
+    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
+    store.register_late_pass(|| box if_let_some_result::OkIfLet);
+    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
+    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
+    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
+    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
+    store.register_late_pass(|| box explicit_write::ExplicitWrite);
+    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
+    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
+        conf.trivial_copy_size_limit,
+        conf.pass_by_value_size_limit,
+        conf.avoid_breaking_exported_api,
+        &sess.target,
+    );
+    store.register_late_pass(move || box pass_by_ref_or_value);
+    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
+    store.register_late_pass(|| box try_err::TryErr);
+    store.register_late_pass(|| box bytecount::ByteCount);
+    store.register_late_pass(|| box infinite_iter::InfiniteIter);
+    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
+    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
+    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
+    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
+    store.register_late_pass(|| box double_comparison::DoubleComparisons);
+    store.register_late_pass(|| box question_mark::QuestionMark);
+    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
+    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
+    store.register_late_pass(|| box map_unit_fn::MapUnit);
+    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
+    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
+    store.register_late_pass(|| box unwrap::Unwrap);
+    store.register_late_pass(|| box duration_subsec::DurationSubsec);
+    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
+    store.register_late_pass(|| box non_copy_const::NonCopyConst);
+    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
+    store.register_late_pass(|| box redundant_clone::RedundantClone);
+    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+    store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api));
+    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
+    store.register_late_pass(|| box transmuting_null::TransmutingNull);
+    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
+    store.register_late_pass(|| box integer_division::IntegerDivision);
+    store.register_late_pass(|| box inherent_to_string::InherentToString);
+    let max_trait_bounds = conf.max_trait_bounds;
+    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
+    store.register_late_pass(|| box comparison_chain::ComparisonChain);
+    store.register_late_pass(|| box mut_key::MutableKeyType);
+    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
+    store.register_early_pass(|| box reference::DerefAddrOf);
+    store.register_early_pass(|| box reference::RefInDeref);
+    store.register_early_pass(|| box double_parens::DoubleParens);
+    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
+    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
+    store.register_early_pass(|| box if_not_else::IfNotElse);
+    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
+    store.register_early_pass(|| box int_plus_one::IntPlusOne);
+    store.register_early_pass(|| box formatting::Formatting);
+    store.register_early_pass(|| box misc_early::MiscEarlyLints);
+    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_early_pass(|| box unused_unit::UnusedUnit);
+    store.register_late_pass(|| box returns::Return);
+    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
+    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
+    store.register_early_pass(|| box precedence::Precedence);
+    store.register_early_pass(|| box needless_continue::NeedlessContinue);
+    store.register_early_pass(|| box redundant_else::RedundantElse);
+    store.register_late_pass(|| box create_dir::CreateDir);
+    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
+    let cargo_ignore_publish = conf.cargo_ignore_publish;
+    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
+    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
+    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
+    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
+    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
+    let literal_representation_threshold = conf.literal_representation_threshold;
+    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
+    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api));
+    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
+    store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive));
+    store.register_late_pass(|| box default::Default::default());
+    store.register_late_pass(|| box unused_self::UnusedSelf);
+    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
+    store.register_late_pass(|| box exit::Exit);
+    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
+    let array_size_threshold = conf.array_size_threshold;
+    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
+    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
+    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
+    store.register_early_pass(|| box as_conversions::AsConversions);
+    store.register_late_pass(|| box let_underscore::LetUnderscore);
+    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
+    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
+    let max_fn_params_bools = conf.max_fn_params_bools;
+    let max_struct_bools = conf.max_struct_bools;
+    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
+    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
+    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
+    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
+    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
+    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
+    store.register_late_pass(|| box dereference::Dereferencing::default());
+    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
+    store.register_late_pass(|| box future_not_send::FutureNotSend);
+    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
+    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
+    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
+    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
+    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
+        single_char_binding_names_threshold,
+    });
+    store.register_late_pass(|| box macro_use::MacroUseImports::default());
+    store.register_late_pass(|| box map_identity::MapIdentity);
+    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
+    store.register_late_pass(|| box repeat_once::RepeatOnce);
+    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
+    store.register_late_pass(|| box self_assignment::SelfAssignment);
+    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
+    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
+    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+    store.register_late_pass(|| box strings::StrToString);
+    store.register_late_pass(|| box strings::StringToString);
+    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
+    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
+    store.register_late_pass(|| box manual_map::ManualMap);
+    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
+    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+    store.register_late_pass(|| box unused_async::UnusedAsync);
+
 }
 
 #[rustfmt::skip]
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 116ad072837..5ae68ba5b2f 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -205,7 +205,7 @@ fn could_use_elision<'tcx>(
         output_visitor.visit_ty(ty);
     }
     for lt in named_generics {
-        input_visitor.visit_generic_param(lt)
+        input_visitor.visit_generic_param(lt);
     }
 
     if input_visitor.abort() || output_visitor.abort() {
@@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
         // `'b` in `'a: 'b` is useless unless used elsewhere in
         // a non-lifetime bound
         if let GenericParamKind::Type { .. } = param.kind {
-            walk_generic_param(self, param)
+            walk_generic_param(self, param);
         }
     }
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index e93b2e36b86..e0c5578bd60 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -231,7 +231,7 @@ impl EarlyLintPass for LiteralDigitGrouping {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -294,7 +294,7 @@ impl LiteralDigitGrouping {
                         }
                     };
                     if should_warn {
-                        warning_type.display(num_lit.format(), cx, lit.span)
+                        warning_type.display(num_lit.format(), cx, lit.span);
                     }
                 }
             }
@@ -424,7 +424,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -446,7 +446,7 @@ impl DecimalLiteralRepresentation {
                 let hex = format!("{:#X}", val);
                 let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
                 let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                    warning_type.display(num_lit.format(), cx, lit.span)
+                    warning_type.display(num_lit.format(), cx, lit.span);
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index ce02ad013be..f0327b5d777 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m
         "to write this more concisely, try",
         format!("&{}{}", muta, object),
         applicability,
-    )
+    );
 }
 
 /// Returns `true` if the type of expr is one that provides `IntoIterator` impls
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 1425d50f560..d07b5a93b67 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -88,10 +88,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
         if let ty::BorrowKind::MutBorrow = bk {
             if let PlaceBase::Local(id) = cmt.place.base {
                 if Some(id) == self.hir_id_low {
-                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
                 if Some(id) == self.hir_id_high {
-                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
             }
         }
@@ -100,10 +100,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
         if let PlaceBase::Local(id) = cmt.place.base {
             if Some(id) == self.hir_id_low {
-                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
             if Some(id) == self.hir_id_high {
-                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index d3406780888..eb82c9c27c3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -1,5 +1,5 @@
 use super::NEEDLESS_COLLECT;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -116,9 +116,10 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                     // Suggest replacing iter_call with iter_replacement, and removing stmt
                     let mut span = MultiSpan::from_span(collect_span);
                     span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
-                    span_lint_and_then(
+                    span_lint_hir_and_then(
                         cx,
                         super::NEEDLESS_COLLECT,
+                        init_expr.hir_id,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index cb2c83e9029..0f6cd5de761 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
                 "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
                 item_str, vec_str, item_str
             ),
-        )
+        );
     }
 
     if !matches!(pat.kind, PatKind::Wild) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 4db6644b9d7..2f7360210ba 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -80,10 +80,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                         }
                     },
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
                 }
@@ -207,7 +207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
                         }
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        self.state = InitializeVisitorState::DontWarn
+                        self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
                 }
@@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
                 return;
             }
         }
-        walk_pat(self, pat)
+        walk_pat(self, pat);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index 55404b87ec9..5f9ebad25e8 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -1,5 +1,5 @@
 use super::WHILE_IMMUTABLE_CONDITION;
-use crate::consts::constant;
+use clippy_utils::consts::constant;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 914b583186c..66479ae264e 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -212,9 +212,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
         let mut suggestions = vec![];
         for ((root, span), path) in used {
             if path.len() == 1 {
-                suggestions.push((span, format!("{}::{}", root, path[0])))
+                suggestions.push((span, format!("{}::{}", root, path[0])));
             } else {
-                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
             }
         }
 
@@ -231,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                     "remove the attribute and import the macro directly, try",
                     help,
                     Applicability::MaybeIncorrect,
-                )
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 23428524dee..61b5fe81fa9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                                           kind_word,
                                           snippet(cx, pattern.span, "..")))]
                             .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
-                        )
+                        );
                     });
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
index 2f579edd6ad..18038dd7819 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 99c35ae3bbf..e1f80ab025c 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
         "remove the `map` call",
         String::new(),
         Applicability::MachineApplicable,
-    )
+    );
 }
 
 fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
@@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     } else {
         span_lint_and_sugg(
             cx,
@@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index fcd37687010..cd3e3b97928 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, miri_to_const, Constant};
 use clippy_utils::diagnostics::{
     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
@@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 "try this",
                 suggestions.join(" | "),
                 Applicability::MaybeIncorrect,
-            )
+            );
         },
     };
 }
@@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
                     cast,
                 ),
                 applicability,
-            )
+            );
         }
     }
 }
@@ -1494,7 +1494,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
                     "consider using the scrutinee and body instead",
                     sugg,
                     applicability,
-                )
+                );
             } else {
                 span_lint_and_sugg(
                     cx,
@@ -1747,7 +1747,7 @@ mod redundant_pattern_match {
             match match_source {
                 MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
                 MatchSource::IfLetDesugar { contains_else_clause } => {
-                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
+                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
                 },
                 MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
                 _ => {},
@@ -1876,7 +1876,7 @@ mod redundant_pattern_match {
                             {
                                 self.res = true;
                             } else {
-                                self.visit_expr(self_arg)
+                                self.visit_expr(self_arg);
                             }
                         }
                         args.iter().for_each(|arg| self.visit_expr(arg));
diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
index a735c616f6e..aca96e06ef2 100644
--- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
@@ -67,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
                                 }
                             }
 
-                            let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+                            let derefs = "*".repeat(derefs_needed);
                             diag.span_suggestion(
                                 param.span,
                                 "try dereferencing",
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 287bff886bf..da428a7b487 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -135,7 +135,7 @@ pub(crate) trait BindInsteadOfMap {
                         .into_iter()
                         .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
                 ),
-            )
+            );
         });
         true
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index ce2e8fa8b10..1a32af5dc7a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -8,7 +8,6 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
-use std::iter;
 
 use super::CLONE_DOUBLE_REF;
 use super::CLONE_ON_COPY;
@@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                             ty = inner;
                             n += 1;
                         }
-                        let refs: String = iter::repeat('&').take(n + 1).collect();
-                        let derefs: String = iter::repeat('*').take(n).collect();
+                        let refs = "&".repeat(n + 1);
+                        let derefs = "*".repeat(n);
                         let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
                         diag.span_suggestion(
                             expr.span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index ecec6da3aa0..f5b4b6bf8ea 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
         "try",
         "copied".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
index 12d560653ed..32d40d97bf4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
@@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
         "try",
         "filter_map".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 28d0e8cd4ae..b4188d9ed30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
 }
 
 fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+    fn strip_angle_brackets(s: &str) -> Option<&str> {
+        s.strip_prefix('<')?.strip_suffix('>')
+    }
+
     let call_site = expr.span.source_callsite();
     if_chain! {
         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
@@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
         if let Some((_, elements)) = snippet_split.split_last();
 
         then {
-            // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
-            if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) {
-                // remove the type specifier from the path elements
-                let without_ts = elements.iter().filter_map(|e| {
-                    if e == type_specifier { None } else { Some((*e).to_string()) }
-                }).collect::<Vec<_>>();
-                // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
-                format!("{}{}", without_ts.join("::"), type_specifier)
-            } else {
-                // type is not explicitly specified so wildcards are needed
-                // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
-                let ty_str = ty.to_string();
-                let start = ty_str.find('<').unwrap_or(0);
-                let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
-                let nb_wildcard = ty_str[start..end].split(',').count();
-                let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
-                format!("{}<{}>", elements.join("::"), wildcards)
+            if_chain! {
+                if let [type_specifier, _] = snippet_split.as_slice();
+                if let Some(type_specifier) = strip_angle_brackets(type_specifier);
+                if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
+                then {
+                    type_specifier.to_string()
+                } else {
+                    // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+                    if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+                        // remove the type specifier from the path elements
+                        let without_ts = elements.iter().filter_map(|e| {
+                            if e == type_specifier { None } else { Some((*e).to_string()) }
+                        }).collect::<Vec<_>>();
+                        // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+                        format!("{}{}", without_ts.join("::"), type_specifier)
+                    } else {
+                        // type is not explicitly specified so wildcards are needed
+                        // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+                        let ty_str = ty.to_string();
+                        let start = ty_str.find('<').unwrap_or(0);
+                        let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+                        let nb_wildcard = ty_str[start..end].split(',').count();
+                        let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+                        format!("{}<{}>", elements.join("::"), wildcards)
+                    }
+                }
             }
         } else {
             ty.to_string()
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 52d7c15332e..68d906c3ea3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index 06b12998b1a..64c09214a76 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir as hir;
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
new file mode 100644
index 00000000000..919e2628c52
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{is_expr_path_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TyS};
+use rustc_span::symbol::sym;
+use std::borrow::Cow;
+
+use super::MANUAL_STR_REPEAT;
+
+enum RepeatKind {
+    String,
+    Char(char),
+}
+
+fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
+    if let ty::Adt(_, subs) = ty.kind() {
+        subs.types().next()
+    } else {
+        None
+    }
+}
+
+fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
+    if let ExprKind::Lit(lit) = &e.kind {
+        match lit.node {
+            LitKind::Str(..) => Some(RepeatKind::String),
+            LitKind::Char(c) => Some(RepeatKind::Char(c)),
+            _ => None,
+        }
+    } else {
+        let ty = cx.typeck_results().expr_ty(e);
+        if is_type_diagnostic_item(cx, ty, sym::string_type)
+            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
+            || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+        {
+            Some(RepeatKind::String)
+        } else {
+            let ty = ty.peel_refs();
+            (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String)
+        }
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    collect_expr: &Expr<'_>,
+    take_expr: &Expr<'_>,
+    take_self_arg: &Expr<'_>,
+    take_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
+        if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type);
+        if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+        if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
+        if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+        if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
+        if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
+        if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
+        let ctxt = collect_expr.span.ctxt();
+        if ctxt == take_expr.span.ctxt();
+        if ctxt == take_self_arg.span.ctxt();
+        then {
+            let mut app = Applicability::MachineApplicable;
+            let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+
+            let val_str = match repeat_kind {
+                RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+                RepeatKind::Char('\'') => r#""'""#.into(),
+                RepeatKind::Char('"') => r#""\"""#.into(),
+                RepeatKind::Char(_) =>
+                    match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+                        Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+                        s @ Cow::Borrowed(_) => s,
+                    },
+                RepeatKind::String =>
+                    Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
+            };
+
+            span_lint_and_sugg(
+                cx,
+                MANUAL_STR_REPEAT,
+                collect_expr.span,
+                "manual implementation of `str::repeat` using iterators",
+                "try this",
+                format!("{}.repeat({})", val_str, count_snip),
+                app
+            )
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e0d29682146..c8ae972f18c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -32,6 +32,7 @@ mod iter_nth_zero;
 mod iter_skip_next;
 mod iterator_step_by_zero;
 mod manual_saturating_arithmetic;
+mod manual_str_repeat;
 mod map_collect_result_unit;
 mod map_flatten;
 mod map_unwrap_or;
@@ -48,6 +49,7 @@ mod single_char_push_string;
 mod skip_while_next;
 mod string_extend_chars;
 mod suspicious_map;
+mod suspicious_splitn;
 mod uninit_assumed_init;
 mod unnecessary_filter_map;
 mod unnecessary_fold;
@@ -61,7 +63,7 @@ mod zst_offset;
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -283,30 +285,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** This is the same as
-    /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
-    ///
-    /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
-    ///
-    /// **Known problems:** Actually *renaming* the function may break clients if
-    /// the function is part of the public interface. In that case, be mindful of
-    /// the stability guarantees you've given your users.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct X;
-    /// impl<'a> X {
-    ///     pub fn as_str(self) -> &'a str {
-    ///         "foo"
-    ///     }
-    /// }
-    /// ```
-    pub WRONG_PUB_SELF_CONVENTION,
-    restriction,
-    "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Checks for usage of `ok().expect(..)`.
     ///
     /// **Why is this bad?** Because you usually call `expect()` on the `Result`
@@ -1657,14 +1635,69 @@ declare_clippy_lint! {
     "replace `.iter().count()` with `.len()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to [`splitn`]
+    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+    /// related functions with either zero or one splits.
+    ///
+    /// **Why is this bad?** These calls don't actually split the value and are
+    /// likely to be intended as a different number.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let s = "";
+    /// for x in s.splitn(1, ":") {
+    ///     // use x
+    /// }
+    ///
+    /// // Good
+    /// let s = "";
+    /// for x in s.splitn(2, ":") {
+    ///     // use x
+    /// }
+    /// ```
+    pub SUSPICIOUS_SPLITN,
+    correctness,
+    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for manual implementations of `str::repeat`
+    ///
+    /// **Why is this bad?** These are both harder to read, as well as less performant.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let x: String = std::iter::repeat('x').take(10).collect();
+    ///
+    /// // Good
+    /// let x: String = "x".repeat(10);
+    /// ```
+    pub MANUAL_STR_REPEAT,
+    perf,
+    "manual implementation of `str::repeat`"
+}
+
 pub struct Methods {
+    avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
 }
 
 impl Methods {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
+    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+            msrv,
+        }
     }
 }
 
@@ -1673,7 +1706,6 @@ impl_lint_pass!(Methods => [
     EXPECT_USED,
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
-    WRONG_PUB_SELF_CONVENTION,
     OK_EXPECT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
@@ -1726,7 +1758,9 @@ impl_lint_pass!(Methods => [
     MAP_COLLECT_RESULT_UNIT,
     FROM_ITER_INSTEAD_OF_COLLECT,
     INSPECT_FOR_EACH,
-    IMPLICIT_CLONE
+    IMPLICIT_CLONE,
+    SUSPICIOUS_SPLITN,
+    MANUAL_STR_REPEAT
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -1838,11 +1872,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     }
                 }
 
-                if sig.decl.implicit_self.has_implicit_self() {
+                if sig.decl.implicit_self.has_implicit_self()
+                    && !(self.avoid_breaking_exported_api
+                        && cx.access_levels.is_exported(impl_item.hir_id()))
+                {
                     wrong_self_convention::check(
                         cx,
                         &name,
-                        item.vis.node.is_pub(),
                         self_ty,
                         first_arg_ty,
                         first_arg.pat.span,
@@ -1915,7 +1951,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 wrong_self_convention::check(
                     cx,
                     &item.ident.name.as_str(),
-                    false,
                     self_ty,
                     first_arg_ty,
                     first_arg_span,
@@ -1951,7 +1986,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
     if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
         match (name, args) {
             ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
-                zst_offset::check(cx, expr, recv)
+                zst_offset::check(cx, expr, recv);
             },
             ("and_then", [arg]) => {
                 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
@@ -1969,6 +2004,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 Some(("map", [m_recv, m_arg], _)) => {
                     map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                 },
+                Some(("take", [take_self_arg, take_arg], _)) => {
+                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
+                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+                    }
+                },
                 _ => {},
             },
             ("count", []) => match method_call!(recv) {
@@ -2012,7 +2052,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                         ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
                         ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
                         ("filter", [f_arg]) => {
-                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                         },
                         ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
                         _ => {},
@@ -2044,6 +2084,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                 }
             },
+            ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
+                suspicious_splitn::check(cx, name, expr, recv, count_arg);
+            },
             ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv, span);
@@ -2058,7 +2101,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
                 Some(("map", [m_recv, m_arg], span)) => {
-                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
                 },
                 _ => {},
             },
@@ -2073,7 +2116,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
     if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
-        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
new file mode 100644
index 00000000000..a271df60572
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -0,0 +1,56 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::SUSPICIOUS_SPLITN;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    method_name: &str,
+    expr: &Expr<'_>,
+    self_arg: &Expr<'_>,
+    count_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
+        if count <= 1;
+        if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
+        let lang_items = cx.tcx.lang_items();
+        if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
+        then {
+            // Ignore empty slice and string literals when used with a literal count.
+            if (matches!(self_arg.kind, ExprKind::Array([]))
+                || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+            ) && matches!(count_arg.kind, ExprKind::Lit(_))
+            {
+                return;
+            }
+
+            let (msg, note_msg) = if count == 0 {
+                (format!("`{}` called with `0` splits", method_name),
+                "the resulting iterator will always return `None`")
+            } else {
+                (format!("`{}` called with `1` split", method_name),
+                if lang_items.slice_impl() == Some(impl_id) {
+                    "the resulting iterator will always return the entire slice followed by `None`"
+                } else {
+                    "the resulting iterator will always return the entire string followed by `None`"
+                })
+            };
+
+            span_lint_and_note(
+                cx,
+                SUSPICIOUS_SPLITN,
+                expr.span,
+                &msg,
+                None,
+                note_msg,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 75517c48a21..4c4034437da 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -87,7 +87,7 @@ pub(super) fn check(
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
             ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
+                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 1773c26c251..a2e09e5ecec 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -6,7 +6,6 @@ use rustc_middle::ty::TyS;
 use rustc_span::source_map::Span;
 use std::fmt;
 
-use super::WRONG_PUB_SELF_CONVENTION;
 use super::WRONG_SELF_CONVENTION;
 
 #[rustfmt::skip]
@@ -21,9 +20,9 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
 
     // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
     // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), 
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), 
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
 ];
 
@@ -85,18 +84,12 @@ impl fmt::Display for Convention {
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: &str,
-    is_pub: bool,
     self_ty: &'tcx TyS<'tcx>,
     first_arg_ty: &'tcx TyS<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
 ) {
-    let lint = if is_pub {
-        WRONG_PUB_SELF_CONVENTION
-    } else {
-        WRONG_SELF_CONVENTION
-    };
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
@@ -142,7 +135,7 @@ pub(super) fn check<'tcx>(
 
             span_lint_and_help(
                 cx,
-                lint,
+                WRONG_SELF_CONVENTION,
                 first_arg_span,
                 &format!(
                     "{} usually take {}",
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index 45948f4d926..ff3473b744e 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{match_def_path, match_trait_method, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index b5d2549242b..804c04fe1b8 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -17,7 +17,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
 use rustc_span::symbol::sym;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
@@ -355,8 +355,10 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
             if let Some(sugg) = Sugg::hir_opt(cx, a);
             then {
-                span_lint_and_then(cx,
+                span_lint_hir_and_then(
+                    cx,
                     SHORT_CIRCUIT_STATEMENT,
+                    expr.hir_id,
                     stmt.span,
                     "boolean short circuit operator in statement may be clearer using an explicit test",
                     |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index dd38316fa25..050b6805b7c 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -310,7 +310,7 @@ impl EarlyLintPass for MiscEarlyLints {
         if in_external_macro(cx.sess(), expr.span) {
             return;
         }
-        double_neg::check(cx, expr)
+        double_neg::check(cx, expr);
     }
 }
 
@@ -334,15 +334,15 @@ impl MiscEarlyLints {
             };
             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
             if lit_snip.starts_with("0x") {
-                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip)
+                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
-                /* nothing to do */
+                // nothing to do
             } else if value != 0 && lit_snip.starts_with('0') {
-                zero_prefixed_literal::check(cx, lit, &lit_snip)
+                zero_prefixed_literal::check(cx, lit, &lit_snip);
             }
         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
             let suffix = float_ty.name_str();
-            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float")
+            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index dfab3e8a931..ec1572c26c2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -93,9 +93,9 @@ impl MissingDoc {
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| {
-            a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
-        });
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
index 64e9dc85466..1414fdc1b11 100644
--- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index cea6fce1195..6efe8ffcde0 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
+                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method");
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 7dfe12cd4eb..25645a0e7a2 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
             _ if !self.found => self.expr_span = Some(expr.span),
             _ => return,
         }
-        walk_expr(self, expr)
+        walk_expr(self, expr);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 3e2b2782ed5..fe3c4455be5 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -121,7 +121,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
         match &p.ty.kind {
             TyKind::Path(None, path) => {
                 if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
-                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
             TyKind::Rptr(lifetime, mut_ty) => {
@@ -129,7 +129,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
                 if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
                     then {
-                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
                     }
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index dd458198637..3b3736fd3a1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                 }
 
                 if is_else_clause(cx.tcx, e) {
-                    snip = snip.blockify()
+                    snip = snip.blockify();
                 }
 
                 span_lint_and_sugg(
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
                         |h: Sugg<'_>| !h,
                         "equality checks against false can be replaced by a negation",
                     ));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Ne => {
                     let true_case = Some((
@@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
                         "inequality checks against true can be replaced by a negation",
                     ));
                     let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Lt => check_comparison(
                     cx,
@@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>(
                             snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
                         ),
                         applicability,
-                    )
+                    );
                 }
             }
 
             match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
                 (Bool(true), Other) => left_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Bool(false), Other) => left_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Other, Other) => no_literal.map_or((), |(h, m)| {
                     let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
@@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>(
                         "try simplifying it as shown",
                         h(left_side, right_side).to_string(),
                         applicability,
-                    )
+                    );
                 }),
                 _ => (),
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index eef3c16730b..dd1dfa2bdfb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -3,16 +3,18 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_automatically_derived;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
+use clippy_utils::{get_parent_expr, in_macro, path_to_local};
 use if_chain::if_chain;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for address of operations (`&`) that are going to
@@ -32,20 +34,70 @@ declare_clippy_lint! {
     /// let x: &i32 = &5;
     /// ```
     pub NEEDLESS_BORROW,
-    nursery,
+    style,
     "taking a reference that is going to be automatically dereferenced"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for `ref` bindings which create a reference to a reference.
+    ///
+    /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let x = Some("");
+    /// if let Some(ref x) = x {
+    ///     // use `x` here
+    /// }
+    ///
+    /// // Good
+    /// let x = Some("");
+    /// if let Some(x) = x {
+    ///     // use `&x` here
+    /// }
+    /// ```
+    pub REF_BINDING_TO_REFERENCE,
+    pedantic,
+    "`ref` binding to a reference"
+}
+
+impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
 #[derive(Default)]
 pub struct NeedlessBorrow {
-    derived_item: Option<LocalDefId>,
+    /// The body the first local was found in. Used to emit lints when the traversal of the body has
+    /// been finished. Note we can't lint at the end of every body as they can be nested within each
+    /// other.
+    current_body: Option<BodyId>,
+    /// The list of locals currently being checked by the lint.
+    /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+    /// This is needed for or patterns where one of the branches can be linted, but another can not
+    /// be.
+    ///
+    /// e.g. `m!(x) | Foo::Bar(ref x)`
+    ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 }
 
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
+struct RefPat {
+    /// Whether every usage of the binding is dereferenced.
+    always_deref: bool,
+    /// The spans of all the ref bindings for this local.
+    spans: Vec<Span>,
+    /// The applicability of this suggestion.
+    app: Applicability,
+    /// All the replacements which need to be made.
+    replacements: Vec<(Span, String)>,
+}
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() || self.derived_item.is_some() {
+        if let Some(local) = path_to_local(e) {
+            self.check_local_usage(cx, e, local);
+        }
+
+        if e.span.from_expansion() {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
@@ -85,50 +137,131 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
             }
         }
     }
+
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if pat.span.from_expansion() || self.derived_item.is_some() {
-            return;
+        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+            if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+                // This binding id has been seen before. Add this pattern to the list of changes.
+                if let Some(prev_pat) = opt_prev_pat {
+                    if in_macro(pat.span) {
+                        // Doesn't match the context of the previous pattern. Can't lint here.
+                        *opt_prev_pat = None;
+                    } else {
+                        prev_pat.spans.push(pat.span);
+                        prev_pat.replacements.push((
+                            pat.span,
+                            snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+                                .0
+                                .into(),
+                        ));
+                    }
+                }
+                return;
+            }
+
+            if_chain! {
+                if !in_macro(pat.span);
+                if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+                // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+                if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+                then {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+                    self.current_body = self.current_body.or(cx.enclosing_body);
+                    self.ref_locals.insert(
+                        id,
+                        Some(RefPat {
+                            always_deref: true,
+                            spans: vec![pat.span],
+                            app,
+                            replacements: vec![(pat.span, snip.into())],
+                        }),
+                    );
+                }
+            }
         }
-        if_chain! {
-            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
-            if mutbl == Mutability::Not;
-            if let ty::Ref(_, _, mutbl) = *tam.kind();
-            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
-            if mutbl == Mutability::Not;
-            then {
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        if Some(body.id()) == self.current_body {
+            for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+                let replacements = pat.replacements;
+                let app = pat.app;
                 span_lint_and_then(
                     cx,
-                    NEEDLESS_BORROW,
-                    pat.span,
+                    if pat.always_deref {
+                        NEEDLESS_BORROW
+                    } else {
+                        REF_BINDING_TO_REFERENCE
+                    },
+                    pat.spans,
                     "this pattern creates a reference to a reference",
                     |diag| {
-                        if let Some(snippet) = snippet_opt(cx, name.span) {
-                            diag.span_suggestion(
-                                pat.span,
-                                "change this to",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
-                )
+                        diag.multipart_suggestion("try this", replacements, app);
+                    },
+                );
             }
+            self.current_body = None;
         }
     }
-
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(item.hir_id());
-        if is_automatically_derived(attrs) {
-            debug_assert!(self.derived_item.is_none());
-            self.derived_item = Some(item.def_id);
-        }
-    }
-
-    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let Some(id) = self.derived_item {
-            if item.def_id == id {
-                self.derived_item = None;
+}
+impl NeedlessBorrow {
+    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+        if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+            if let Some(pat) = outer_pat {
+                // Check for auto-deref
+                if !matches!(
+                    cx.typeck_results().expr_adjustments(e),
+                    [
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        ..
+                    ]
+                ) {
+                    match get_parent_expr(cx, e) {
+                        // Field accesses are the same no matter the number of references.
+                        Some(Expr {
+                            kind: ExprKind::Field(..),
+                            ..
+                        }) => (),
+                        Some(&Expr {
+                            span,
+                            kind: ExprKind::Unary(UnOp::Deref, _),
+                            ..
+                        }) if !in_macro(span) => {
+                            // Remove explicit deref.
+                            let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+                            pat.replacements.push((span, snip.into()));
+                        },
+                        Some(parent) if !in_macro(parent.span) => {
+                            // Double reference might be needed at this point.
+                            if parent.precedence().order() == PREC_POSTFIX {
+                                // Parentheses would be needed here, don't lint.
+                                *outer_pat = None;
+                            } else {
+                                pat.always_deref = false;
+                                let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+                                pat.replacements.push((e.span, format!("&{}", snip)));
+                            }
+                        },
+                        _ if !in_macro(e.span) => {
+                            // Double reference might be needed at this point.
+                            pat.always_deref = false;
+                            let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+                            pat.replacements.push((e.span, format!("&{}", snip)));
+                        },
+                        // Edge case for macros. The span of the identifier will usually match the context of the
+                        // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+                        // macros
+                        _ => *outer_pat = None,
+                    }
+                }
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 079b6642d58..a723a472a25 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -142,10 +142,10 @@ impl<'tcx> Visitor<'tcx> for RetCollector {
         match expr.kind {
             ExprKind::Ret(..) => {
                 if self.loop_depth > 0 && !self.ret_in_loop {
-                    self.ret_in_loop = true
+                    self.ret_in_loop = true;
                 }
 
-                self.spans.push(expr.span)
+                self.spans.push(expr.span);
             },
 
             ExprKind::Loop(..) => {
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 0704173a011..c824f6f54b5 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
                         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"
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 34fd012572f..d5e1ea6d242 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -1,3 +1,4 @@
+use clippy_utils::consts::{self, Constant};
 use clippy_utils::diagnostics::span_lint;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -5,8 +6,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{self, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for multiplication by -1 as a form of negation.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index cfcaf509471..b2206a82208 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
 use rustc_errors::Applicability;
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Semi(expr) = stmt.kind {
             if has_no_effect(cx, expr) {
-                span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
+                span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
             } else if let Some(reduced) = reduce_expression(cx, expr) {
                 let mut snippet = String::new();
                 for e in reduced {
@@ -106,14 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
                         return;
                     }
                 }
-                span_lint_and_sugg(
+                span_lint_hir_and_then(
                     cx,
                     UNNECESSARY_OPERATION,
+                    expr.hir_id,
                     stmt.span,
                     "statement can be reduced",
-                    "replace it with",
-                    snippet,
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable);
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 4c8bceaf2cb..5292af5f076 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -126,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[
     &["args", "arms"],
     &["qpath", "path"],
     &["lit", "lint"],
+    &["wparam", "lparam"],
 ];
 
 struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs
index 9efe45336bf..fded48038e3 100644
--- a/src/tools/clippy/clippy_lints/src/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/open_options.rs
@@ -123,7 +123,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `create` is called more than once",
                     );
                 } else {
-                    create = true
+                    create = true;
                 }
                 create_arg = create_arg || (arg == Argument::True);
             },
@@ -136,7 +136,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `append` is called more than once",
                     );
                 } else {
-                    append = true
+                    append = true;
                 }
                 append_arg = append_arg || (arg == Argument::True);
             },
@@ -149,7 +149,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `truncate` is called more than once",
                     );
                 } else {
-                    truncate = true
+                    truncate = true;
                 }
                 truncate_arg = truncate_arg || (arg == Argument::True);
             },
@@ -162,7 +162,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `read` is called more than once",
                     );
                 } else {
-                    read = true
+                    read = true;
                 }
                 read_arg = read_arg || (arg == Argument::True);
             },
@@ -175,7 +175,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `write` is called more than once",
                     );
                 } else {
-                    write = true
+                    write = true;
                 }
                 write_arg = write_arg || (arg == Argument::True);
             },
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 6b64846c24d..f6a70478559 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -102,10 +102,16 @@ declare_clippy_lint! {
 pub struct PassByRefOrValue {
     ref_min_size: u64,
     value_max_size: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl<'tcx> PassByRefOrValue {
-    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
+    pub fn new(
+        ref_min_size: Option<u64>,
+        value_max_size: u64,
+        avoid_breaking_exported_api: bool,
+        target: &Target,
+    ) -> Self {
         let ref_min_size = ref_min_size.unwrap_or_else(|| {
             let bit_width = u64::from(target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
@@ -120,10 +126,14 @@ impl<'tcx> PassByRefOrValue {
         Self {
             ref_min_size,
             value_max_size,
+            avoid_breaking_exported_api,
         }
     }
 
     fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
+        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+            return;
+        }
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 
         let fn_sig = cx.tcx.fn_sig(fn_def_id);
@@ -184,7 +194,6 @@ impl<'tcx> PassByRefOrValue {
                     }
 
                     if_chain! {
-                        if !cx.access_levels.is_exported(hir_id);
                         if is_copy(cx, ty);
                         if !is_self_ty(input);
                         if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index b0674f90678..12c44436874 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -211,7 +211,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     ];
 
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 30bee213900..d66bac52243 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -88,7 +88,7 @@ impl QuestionMark {
                         "replace it with",
                         replacement_str,
                         applicability,
-                    )
+                    );
                 }
             }
         }
@@ -129,7 +129,7 @@ impl QuestionMark {
                     "replace it with",
                     replacement,
                     applicability,
-                )
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 7169f96eaf1..ae5f0627fd6 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 92921bedf4d..8f56a21ac5b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -57,7 +57,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
             self.found_return = true;
         }
 
-        ast_visit::walk_expr(self, ex)
+        ast_visit::walk_expr(self, ex);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index e091095de13..05f9e01acb4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 4b5306de58e..75151167454 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{match_def_path, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
index 560a5e7c920..b479c40bca6 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::in_macro;
 use clippy_utils::source::snippet;
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index b565c77aaec..251d527c265 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(block, _) = body.value.kind {
@@ -241,7 +241,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa
                 if let Some(snippet) = snippet_opt(cx, inner_span) {
                     diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                 }
-            })
+            });
         },
         None => match replacement {
             RetReplacement::Empty => {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 553987a426b..16e4d73851f 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -8,11 +8,11 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
-    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
-    /// but is not followed by a semicolon.
+    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns
+    /// `()` but is not followed by a semicolon.
     ///
-    /// **Why is this bad?** The semicolon might be optional but when
-    /// extending the block with new code, it doesn't require a change in previous last line.
+    /// **Why is this bad?** The semicolon might be optional but when extending the block with new
+    /// code, it doesn't require a change in previous last line.
     ///
     /// **Known problems:** None.
     ///
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub SEMICOLON_IF_NOTHING_RETURNED,
-    restriction,
+    pedantic,
     "add a semicolon if nothing is returned"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index d6101bd5e36..ac3f7ebd14b 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -120,7 +120,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo
     let mut bindings = Vec::with_capacity(decl.inputs.len());
     for arg in iter_input_pats(decl, body) {
         if let PatKind::Binding(.., ident, _) = arg.pat.kind {
-            bindings.push((ident.name, ident.span))
+            bindings.push((ident.name, ident.span));
         }
     }
     check_expr(cx, &body.value, &mut bindings);
@@ -156,7 +156,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
         ..
     } = *local;
     if let Some(t) = *ty {
-        check_ty(cx, t, bindings)
+        check_ty(cx, t, bindings);
     }
     if let Some(o) = *init {
         check_expr(cx, o, bindings);
@@ -324,14 +324,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
     }
     match expr.kind {
         ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
-            check_expr(cx, e, bindings)
+            check_expr(cx, e, bindings);
         },
         ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
         ExprKind::Array(v) | ExprKind::Tup(v) => {
             for e in v {
-                check_expr(cx, e, bindings)
+                check_expr(cx, e, bindings);
             }
         },
         ExprKind::If(cond, then, ref otherwise) => {
@@ -374,7 +374,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(
         TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
         TyKind::Tup(tup) => {
             for t in tup {
-                check_ty(cx, t, bindings)
+                check_ty(cx, t, bindings);
             }
         },
         TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index a45bb102389..1eaad438237 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -70,7 +70,7 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
     for item in items {
         track_uses(
             cx,
-            &item,
+            item,
             &mut imports_reused_with_self,
             &mut single_use_usages,
             &mut macros,
@@ -117,7 +117,7 @@ fn track_uses(
 
     match &item.kind {
         ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
-            check_mod(cx, &items);
+            check_mod(cx, items);
         },
         ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
             macros.push(item.ident.name);
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index a9ae2b77119..e5c58d70b60 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -158,7 +158,7 @@ impl SlowVectorInit {
     ) {
         match initialization {
             InitializationType::Extend(e) | InitializationType::Resize(e) => {
-                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization")
+                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
             },
         };
     }
@@ -290,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
             if let Some(s) = block.stmts.get(0) {
-                self.visit_stmt(s)
+                self.visit_stmt(s);
             }
 
             self.initialization_found = false;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 4272935bc31..bb707f78fcc 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -59,7 +59,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub SUSPICIOUS_OPERATION_GROUPINGS,
-    style,
+    nursery,
     "groupings of binary operations that look suspiciously like typos"
 }
 
@@ -266,7 +266,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit
         "did you mean",
         sugg,
         applicability,
-    )
+    );
 }
 
 fn ident_swap_sugg(
@@ -475,7 +475,7 @@ impl Add for IdentLocation {
 
 impl AddAssign for IdentLocation {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
@@ -506,7 +506,7 @@ impl Add for IdentDifference {
 
 impl AddAssign for IdentDifference {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index b0589b0512e..74a94db1800 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -3,6 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::{in_macro, SpanlessHash};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
@@ -100,7 +101,7 @@ impl TraitBounds {
             hasher.hash_ty(ty);
             hasher.finish()
         };
-        let mut map = FxHashMap::default();
+        let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
             if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
index 888ecab1046..b57d158293d 100644
--- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_expr_path_def_path, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index d9b47a699dc..70b9e8adef8 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
         match item.kind {
             TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
-                self.check_ty(cx, ty, CheckTyContext::default())
+                self.check_ty(cx, ty, CheckTyContext::default());
             },
             TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
             TraitItemKind::Type(..) => (),
@@ -433,7 +433,7 @@ impl Types {
             },
             TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
                 context.is_nested_call = true;
-                self.check_ty(cx, ty, context)
+                self.check_ty(cx, ty, context);
             },
             TyKind::Tup(tys) => {
                 context.is_nested_call = true;
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d81e31f5a21..45291a120ed 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Lit(ref lit) = expr.kind {
             if let LitKind::Str(_, _) = lit.node {
-                check_str(cx, lit.span, expr.hir_id)
+                check_str(cx, lit.span, expr.hir_id);
             }
         }
     }
@@ -82,7 +82,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
     for c in s {
         if c as u32 > 0x7F {
             for d in c.escape_unicode() {
-                result.push(d)
+                result.push(d);
             }
         } else {
             result.push(c);
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index f2f1410aed7..a85ffa6aa95 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk};
 use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -52,7 +52,19 @@ declare_clippy_lint! {
     "functions that only return `Ok` or `Some`"
 }
 
-declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+pub struct UnnecessaryWraps {
+    avoid_breaking_exported_api: bool,
+}
+
+impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl UnnecessaryWraps {
+    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
     fn check_fn(
@@ -66,13 +78,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
     ) {
         // Abort if public function/method or closure.
         match fn_kind {
-            FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
-                if visibility.node.is_pub() {
+            FnKind::ItemFn(..) | FnKind::Method(..) => {
+                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
                     return;
                 }
             },
             FnKind::Closure => return,
-            FnKind::Method(..) => (),
         }
 
         // Abort if the method is implementing a trait or of it a trait method.
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index c27a6d4e347..ee082d30d93 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
 
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
-    while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
+    while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
         if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
             call = &args[0];
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 4ac2ec55b98..0b58c6c0917 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Ident;
@@ -38,12 +38,14 @@ declare_clippy_lint! {
 
 #[derive(Default)]
 pub struct UpperCaseAcronyms {
+    avoid_breaking_exported_api: bool,
     upper_case_acronyms_aggressive: bool,
 }
 
 impl UpperCaseAcronyms {
-    pub fn new(aggressive: bool) -> Self {
+    pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
         Self {
+            avoid_breaking_exported_api,
             upper_case_acronyms_aggressive: aggressive,
         }
     }
@@ -72,7 +74,7 @@ fn correct_ident(ident: &str) -> String {
     ident
 }
 
-fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
     let span = ident.span;
     let ident = &ident.as_str();
     let corrected = correct_ident(ident);
@@ -92,27 +94,31 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
             "consider making the acronym lowercase, except the initial letter",
             corrected,
             Applicability::MaybeIncorrect,
-        )
+        );
     }
 }
 
-impl EarlyLintPass for UpperCaseAcronyms {
-    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+impl LateLintPass<'_> for UpperCaseAcronyms {
+    fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
-        if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
-            if matches!(
-                it.kind,
-                ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
-            ) {
+        if in_external_macro(cx.sess(), it.span)
+            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+        {
+            return;
+        }
+        match it.kind {
+            ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
                 check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
-            } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+            },
+            ItemKind::Enum(ref enumdef, _) => {
                 // check enum variants seperately because again we only want to lint on private enums and
                 // the fn check_variant does not know about the vis of the enum of its variants
                 enumdef
                     .variants
                     .iter()
                     .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
-            }
+            },
+            _ => {},
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 2ad6fa77f48..254b104bdef 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -356,7 +356,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector {
     fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
         self.types_to_skip.push(hir_ty.hir_id);
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -385,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> {
             }
         }
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index e70f8a09ebe..39ef170ae36 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     LitKind::Str(ref text, _) => {
                         let str_pat = self.next("s");
                         println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
-                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str())
+                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str());
                     },
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index fd2dddb3b96..0e33ae740d9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -122,7 +122,9 @@ macro_rules! define_Conf {
 
 // N.B., this macro is parsed by util/lintlib.py
 define_Conf! {
-    /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
+    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
+    (avoid_breaking_exported_api: bool = true),
+    /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
     (msrv: Option<String> = None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
@@ -208,15 +210,13 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
         .map_or_else(|| PathBuf::from("."), PathBuf::from);
     loop {
         for config_file_name in &CONFIG_FILE_NAMES {
-            let config_file = current.join(config_file_name);
-            match fs::metadata(&config_file) {
-                // Only return if it's a file to handle the unlikely situation of a directory named
-                // `clippy.toml`.
-                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
-                // Return the error if it's something other than `NotFound`; otherwise we didn't
-                // find the project file yet, and continue searching.
-                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
-                _ => {},
+            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
+                match fs::metadata(&config_file) {
+                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
+                    Err(e) => return Err(e),
+                    Ok(md) if md.is_dir() => {},
+                    Ok(_) => return Ok(Some(config_file)),
+                }
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index ee7be24eae8..b1523e032af 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
@@ -1100,7 +1100,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
                 IF_CHAIN_STYLE,
                 if_chain_local_span(cx, local, if_chain_span),
                 "`let` expression should be inside `then { .. }`",
-            )
+            );
         }
     }
 
@@ -1141,7 +1141,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
         if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
             && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
         {
-            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index e9fa043b20f..46af03663b8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -379,7 +379,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// }
     /// ```
     fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
-        if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
             // Normal lint
             if_chain! {
                 // item validation
@@ -489,7 +489,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
         .hir()
         .attrs(item.hir_id())
         .iter()
-        .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string()))
+        .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
         .reduce(|mut acc, sym| {
             acc.push_str(&sym);
             acc.push('\n');
@@ -596,7 +596,7 @@ fn extract_emission_info<'hir>(
     let mut multi_part = false;
 
     for arg in args {
-        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg));
+        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
 
         if match_type(cx, arg_ty, &paths::LINT) {
             // If we found the lint arg, extract the lint name
@@ -671,7 +671,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
             if let ExprKind::Path(qpath) = &expr.kind;
             if let QPath::Resolved(_, path) = qpath;
 
-            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
             if match_type(self.cx, expr_ty, &paths::LINT);
             then {
                 if let hir::def::Res::Def(DefKind::Static, _) = path.res {
@@ -730,7 +730,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
     }
 
     fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
-        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 
         if_chain! {
             if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
@@ -818,7 +818,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
                     .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
                 if found_function {
                     // These functions are all multi part suggestions
-                    self.add_single_span_suggestion()
+                    self.add_single_span_suggestion();
                 }
             },
             ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index febd4b6ff7b..1d5b7c98d31 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -1,5 +1,5 @@
-use crate::consts::{constant, Constant};
 use crate::rustc_target::abi::LayoutOf;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
index ec209b30951..3ab68df2b6d 100644
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
                 "use of `File::read_to_string`",
                 None,
                 "consider using `fs::read_to_string` instead",
-            )
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index d0e79efa70d..5229a705865 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -300,7 +300,7 @@ impl EarlyLintPass for Write {
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         } else if mac.path == sym!(writeln) {
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 350b1cf25ff..a1ea743ba80 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index c0584e1e226..0318c483959 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -115,7 +115,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
     for attr in get_attr(sess, attrs, name) {
         if let Some(ref value) = attr.value_str() {
             if let Ok(value) = FromStr::from_str(&value.as_str()) {
-                f(value)
+                f(value);
             } else {
                 sess.span_err(attr.span, "not a number");
             }
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 2a305d8bcbe..0d7fdeeb920 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -229,25 +229,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
-            ExprKind::Block(ref block, _) => self.block(block),
+            ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
-            ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
-            ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
-            ExprKind::Repeat(ref value, _) => {
+            ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
+            ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
+            ExprKind::Repeat(value, _) => {
                 let n = match self.typeck_results.expr_ty(e).kind() {
                     ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
-            ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
+            ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
                 UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
-            ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
-            ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
-            ExprKind::Call(ref callee, ref args) => {
+            ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
+            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+            ExprKind::Call(callee, args) => {
                 // We only handle a few const functions for now.
                 if_chain! {
                     if args.is_empty();
@@ -273,8 +273,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     }
                 }
             },
-            ExprKind::Index(ref arr, ref index) => self.index(arr, index),
-            ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
+            ExprKind::Index(arr, index) => self.index(arr, index),
+            ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
             // TODO: add other expressions.
             _ => None,
         }
@@ -349,7 +349,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     )
                     .ok()
                     .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
-                let result = miri_to_const(&result);
+                let result = miri_to_const(result);
                 if result.is_some() {
                     self.needed_resolution = true;
                 }
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index a4efae54894..7c94474cb35 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -167,7 +167,7 @@ pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
     hir_id: HirId,
-    sp: Span,
+    sp: impl Into<MultiSpan>,
     msg: &str,
     f: impl FnOnce(&mut DiagnosticBuilder<'_>),
 ) {
@@ -223,7 +223,7 @@ pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg:
 where
     I: IntoIterator<Item = (Span, String)>,
 {
-    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
+    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
 }
 
 /// Create a suggestion made from several `span → replacement`.
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 0c0e4d3b4ce..8be36756b33 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -58,7 +58,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
     }
 
     match expr.kind {
-        hir::ExprKind::Call(ref path, ref args)
+        hir::ExprKind::Call(path, args)
             if matches!(
                 path.kind,
                 hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
@@ -70,7 +70,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
                 limits: ast::RangeLimits::Closed,
             })
         },
-        hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+        hir::ExprKind::Struct(path, fields, None) => match path {
             hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
                 start: None,
                 end: None,
@@ -112,7 +112,7 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
     // }
     // ```
     if_chain! {
-        if let Some(ref expr) = local.init;
+        if let Some(expr) = local.init;
         if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
         then {
             return true;
@@ -140,14 +140,14 @@ pub fn for_loop<'tcx>(
     expr: &'tcx hir::Expr<'tcx>,
 ) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> {
     if_chain! {
-        if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
-        if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
+        if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
+        if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
         if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
-        if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+        if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind;
         if block.expr.is_none();
         if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
-        if let hir::StmtKind::Local(ref local) = let_stmt.kind;
-        if let hir::StmtKind::Expr(ref expr) = body.kind;
+        if let hir::StmtKind::Local(local) = let_stmt.kind;
+        if let hir::StmtKind::Expr(expr) = body.kind;
         then {
             return Some((&*local.pat, &iterargs[0], expr, arms[0].span));
         }
@@ -182,7 +182,7 @@ pub enum VecArgs<'a> {
 /// from `vec!`.
 pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
     if_chain! {
-        if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let hir::ExprKind::Call(fun, args) = expr.kind;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if is_expn_of(fun.span, "vec").is_some();
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
@@ -194,8 +194,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
             else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                 // `vec![a, b, c]` case
                 if_chain! {
-                    if let hir::ExprKind::Box(ref boxed) = args[0].kind;
-                    if let hir::ExprKind::Array(ref args) = boxed.kind;
+                    if let hir::ExprKind::Box(boxed) = args[0].kind;
+                    if let hir::ExprKind::Array(args) = boxed.kind;
                     then {
                         return Some(VecArgs::Vec(&*args));
                     }
@@ -227,7 +227,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
     /// compared
     fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
         if_chain! {
-            if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
+            if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
             if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
@@ -238,12 +238,12 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
         None
     }
 
-    if let ExprKind::Block(ref block, _) = e.kind {
+    if let ExprKind::Block(block, _) = e.kind {
         if block.stmts.len() == 1 {
-            if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind {
+            if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
                 // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
                 if_chain! {
-                    if let ExprKind::If(ref clause, _, _)  = matchexpr.kind;
+                    if let ExprKind::If(clause, _, _)  = matchexpr.kind;
                     if let ExprKind::Unary(UnOp::Not, condition) = clause.kind;
                     then {
                         return Some(vec![condition]);
@@ -252,8 +252,8 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
 
                 // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
                 if_chain! {
-                    if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
-                    if let Some(ref matchblock_expr) = matchblock.expr;
+                    if let ExprKind::Block(matchblock,_) = matchexpr.kind;
+                    if let Some(matchblock_expr) = matchblock.expr;
                     then {
                         return ast_matchblock(matchblock_expr);
                     }
@@ -261,7 +261,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
             }
         } else if let Some(matchblock_expr) = block.expr {
             // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
-            return ast_matchblock(&matchblock_expr);
+            return ast_matchblock(matchblock_expr);
         }
     }
     None
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 3b01158acd9..a21ad42c061 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -2,20 +2,19 @@ use crate::consts::{constant_context, constant_simple};
 use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+    StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
 use rustc_middle::ty::TypeckResults;
 use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
 /// Type used to check whether two ast are the same. This is different from the
 /// operator
@@ -95,12 +94,12 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
 impl HirEqInterExpr<'_, '_, '_> {
     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+            (&StmtKind::Local(l), &StmtKind::Local(r)) => {
                 // This additional check ensures that the type of the locals are equivalent even if the init
                 // expression or type have some inferred parts.
                 if let Some(typeck) = self.inner.maybe_typeck_results {
-                    let l_ty = typeck.pat_ty(&l.pat);
-                    let r_ty = typeck.pat_ty(&r.pat);
+                    let l_ty = typeck.pat_ty(l.pat);
+                    let r_ty = typeck.pat_ty(r.pat);
                     if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
                         return false;
                     }
@@ -110,11 +109,9 @@ impl HirEqInterExpr<'_, '_, '_> {
                 // these only get added if the init and type is equal.
                 both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
-                    && self.eq_pat(&l.pat, &r.pat)
-            },
-            (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
-                self.eq_expr(l, r)
+                    && self.eq_pat(l.pat, r.pat)
             },
+            (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
             _ => false,
         }
     }
@@ -165,12 +162,18 @@ impl HirEqInterExpr<'_, '_, '_> {
                 left.eq(right)
             },
             _ => {
-                over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
+                over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
                     && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
             },
         }
     }
 
+    pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+        let cx = self.inner.cx;
+        let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+        eval_const(left) == eval_const(right)
+    }
+
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
@@ -192,20 +195,20 @@ impl HirEqInterExpr<'_, '_, '_> {
             &reduce_exprkind(self.inner.cx, &left.kind),
             &reduce_exprkind(self.inner.cx, &right.kind),
         ) {
-            (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
+            (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
             },
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
+            (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
                 self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
+            (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
                 self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
-            (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
+            (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
+            (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
                     || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
                         l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
@@ -215,58 +218,50 @@ impl HirEqInterExpr<'_, '_, '_> {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
                     && both(le, re, |l, r| self.eq_expr(l, r))
             },
-            (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
+            (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
-            | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+            (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
                 self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
             },
-            (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
+            (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
             },
-            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
-                self.eq_expr(la, ra) && self.eq_expr(li, ri)
-            },
-            (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
+            (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+            (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
-            (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+            (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
+            (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
                 ls == rs
                     && self.eq_expr(le, re)
                     && over(la, ra, |l, r| {
-                        self.eq_pat(&l.pat, &r.pat)
+                        self.eq_pat(l.pat, r.pat)
                             && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
-                            && self.eq_expr(&l.body, &r.body)
+                            && self.eq_expr(l.body, r.body)
                     })
             },
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
-                let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
-                let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
-                self.eq_expr(le, re) && ll == rl
+            (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
+                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
+            (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
                 self.eq_qpath(l_path, r_path)
                     && both(lo, ro, |l, r| self.eq_expr(l, r))
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
-            (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
+            (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
-            (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
+            (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
             _ => false,
         };
         is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
@@ -277,7 +272,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
+        left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
     }
 
     fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
@@ -290,6 +285,7 @@ impl HirEqInterExpr<'_, '_, '_> {
 
     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
         match (left, right) {
+            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
             (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
             _ => false,
@@ -308,11 +304,11 @@ impl HirEqInterExpr<'_, '_, '_> {
     /// Checks whether two patterns are the same.
     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
-            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+            (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
+            (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
             },
-            (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
+            (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
             (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
@@ -323,15 +319,13 @@ impl HirEqInterExpr<'_, '_, '_> {
                 eq
             },
             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
-            (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
-                ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
-            },
+            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+            (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
                 both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
             },
-            (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
-            (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
+            (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
+            (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
                 over(ls, rs, |l, r| self.eq_pat(l, r))
                     && over(le, re, |l, r| self.eq_pat(l, r))
                     && both(li, ri, |l, r| self.eq_pat(l, r))
@@ -344,10 +338,10 @@ impl HirEqInterExpr<'_, '_, '_> {
     #[allow(clippy::similar_names)]
     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
         match (left, right) {
-            (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
+            (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
                 both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
             },
-            (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
+            (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
             (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
@@ -359,14 +353,14 @@ impl HirEqInterExpr<'_, '_, '_> {
         match (left.res, right.res) {
             (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
             (Res::Local(_), _) | (_, Res::Local(_)) => false,
-            _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
+            _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
         }
     }
 
     fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
         if !(left.parenthesized || right.parenthesized) {
-            over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
-                && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
+            over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
+                && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
         } else if left.parenthesized && right.parenthesized {
             over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
                 && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
@@ -390,12 +384,9 @@ impl HirEqInterExpr<'_, '_, '_> {
     #[allow(clippy::similar_names)]
     fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
-            (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
-                let cx = self.inner.cx;
-                let eval_const =
-                    |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
-                self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+            (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+            (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
+                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -404,14 +395,14 @@ impl HirEqInterExpr<'_, '_, '_> {
                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
             },
             (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+            (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
             (&TyKind::Infer, &TyKind::Infer) => true,
             _ => false,
         }
     }
 
     fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
+        left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
     }
 }
 
@@ -519,7 +510,7 @@ pub struct SpanlessHash<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    s: StableHasher,
+    s: FxHasher,
 }
 
 impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
@@ -527,7 +518,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            s: StableHasher::new(),
+            s: FxHasher::default(),
         }
     }
 
@@ -540,17 +531,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             self.hash_stmt(s);
         }
 
-        if let Some(ref e) = b.expr {
+        if let Some(e) = b.expr {
             self.hash_expr(e);
         }
 
-        match b.rules {
-            BlockCheckMode::DefaultBlock => 0,
-            BlockCheckMode::UnsafeBlock(_) => 1,
-            BlockCheckMode::PushUnsafeBlock(_) => 2,
-            BlockCheckMode::PopUnsafeBlock(_) => 3,
-        }
-        .hash(&mut self.s);
+        std::mem::discriminant(&b.rules).hash(&mut self.s);
     }
 
     #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
@@ -561,21 +546,16 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
-        simple_const.is_some().hash(&mut self.s);
-
-        if let Some(e) = simple_const {
-            return e.hash(&mut self.s);
+        simple_const.hash(&mut self.s);
+        if simple_const.is_some() {
+            return;
         }
 
         std::mem::discriminant(&e.kind).hash(&mut self.s);
 
         match e.kind {
-            ExprKind::AddrOf(kind, m, ref e) => {
-                match kind {
-                    BorrowKind::Ref => 0,
-                    BorrowKind::Raw => 1,
-                }
-                .hash(&mut self.s);
+            ExprKind::AddrOf(kind, m, e) => {
+                std::mem::discriminant(&kind).hash(&mut self.s);
                 m.hash(&mut self.s);
                 self.hash_expr(e);
             },
@@ -584,22 +564,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::Assign(ref l, ref r, _) => {
+            ExprKind::Assign(l, r, _) => {
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::AssignOp(ref o, ref l, ref r) => {
-                o.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::AssignOp(ref o, l, r) => {
+                std::mem::discriminant(&o.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::Block(ref b, _) => {
+            ExprKind::Block(b, _) => {
                 self.hash_block(b);
             },
-            ExprKind::Binary(op, ref l, ref r) => {
-                op.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Binary(op, l, r) => {
+                std::mem::discriminant(&op.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
@@ -607,39 +585,35 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 if let Some(i) = i.label {
                     self.hash_name(i.ident.name);
                 }
-                if let Some(ref j) = *j {
+                if let Some(j) = *j {
                     self.hash_expr(&*j);
                 }
             },
-            ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
+            ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
                 self.hash_expr(e);
             },
-            ExprKind::Call(ref fun, args) => {
+            ExprKind::Call(fun, args) => {
                 self.hash_expr(fun);
                 self.hash_exprs(args);
             },
-            ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
+            ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
                 self.hash_expr(e);
                 self.hash_ty(ty);
             },
             ExprKind::Closure(cap, _, eid, _, _) => {
-                match cap {
-                    CaptureBy::Value => 0,
-                    CaptureBy::Ref => 1,
-                }
-                .hash(&mut self.s);
+                std::mem::discriminant(&cap).hash(&mut self.s);
                 // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
-            ExprKind::Field(ref e, ref f) => {
+            ExprKind::Field(e, ref f) => {
                 self.hash_expr(e);
                 self.hash_name(f.name);
             },
-            ExprKind::Index(ref a, ref i) => {
+            ExprKind::Index(a, i) => {
                 self.hash_expr(a);
                 self.hash_expr(i);
             },
-            ExprKind::InlineAsm(ref asm) => {
+            ExprKind::InlineAsm(asm) => {
                 for piece in asm.template {
                     match piece {
                         InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
@@ -694,22 +668,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
-            ExprKind::Loop(ref b, ref i, ..) => {
+            ExprKind::Loop(b, ref i, ..) => {
                 self.hash_block(b);
                 if let Some(i) = *i {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::If(ref cond, ref then, ref else_opt) => {
-                let c: fn(_, _, _) -> _ = ExprKind::If;
-                c.hash(&mut self.s);
+            ExprKind::If(cond, then, ref else_opt) => {
                 self.hash_expr(cond);
-                self.hash_expr(&**then);
-                if let Some(ref e) = *else_opt {
+                self.hash_expr(then);
+                if let Some(e) = *else_opt {
                     self.hash_expr(e);
                 }
             },
-            ExprKind::Match(ref e, arms, ref s) => {
+            ExprKind::Match(e, arms, ref s) => {
                 self.hash_expr(e);
 
                 for arm in arms {
@@ -717,39 +689,39 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     if let Some(ref e) = arm.guard {
                         self.hash_guard(e);
                     }
-                    self.hash_expr(&arm.body);
+                    self.hash_expr(arm.body);
                 }
 
                 s.hash(&mut self.s);
             },
-            ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
+            ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
                 self.hash_name(path.ident.name);
                 self.hash_exprs(args);
             },
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
             },
-            ExprKind::Repeat(ref e, ref l_id) => {
+            ExprKind::Repeat(e, ref l_id) => {
                 self.hash_expr(e);
                 self.hash_body(l_id.body);
             },
             ExprKind::Ret(ref e) => {
-                if let Some(ref e) = *e {
+                if let Some(e) = *e {
                     self.hash_expr(e);
                 }
             },
             ExprKind::Path(ref qpath) => {
                 self.hash_qpath(qpath);
             },
-            ExprKind::Struct(ref path, fields, ref expr) => {
+            ExprKind::Struct(path, fields, ref expr) => {
                 self.hash_qpath(path);
 
                 for f in fields {
                     self.hash_name(f.ident.name);
-                    self.hash_expr(&f.expr);
+                    self.hash_expr(f.expr);
                 }
 
-                if let Some(ref e) = *expr {
+                if let Some(e) = *expr {
                     self.hash_expr(e);
                 }
             },
@@ -759,8 +731,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Array(v) => {
                 self.hash_exprs(v);
             },
-            ExprKind::Unary(lop, ref le) => {
-                lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Unary(lop, le) => {
+                std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
             },
         }
@@ -773,19 +745,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     }
 
     pub fn hash_name(&mut self, n: Symbol) {
-        n.as_str().hash(&mut self.s);
+        n.hash(&mut self.s);
     }
 
     pub fn hash_qpath(&mut self, p: &QPath<'_>) {
         match *p {
-            QPath::Resolved(_, ref path) => {
+            QPath::Resolved(_, path) => {
                 self.hash_path(path);
             },
-            QPath::TypeRelative(_, ref path) => {
+            QPath::TypeRelative(_, path) => {
                 self.hash_name(path.ident.name);
             },
             QPath::LangItem(lang_item, ..) => {
-                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&lang_item).hash(&mut self.s);
             },
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -795,7 +767,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
             PatKind::Binding(ann, _, _, pat) => {
-                ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&ann).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
@@ -815,11 +787,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 if let Some(e) = e {
                     self.hash_expr(e);
                 }
-                i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&i).hash(&mut self.s);
             },
-            PatKind::Ref(pat, m) => {
+            PatKind::Ref(pat, mu) => {
                 self.hash_pat(pat);
-                m.hash(&mut self.s);
+                std::mem::discriminant(&mu).hash(&mut self.s);
             },
             PatKind::Slice(l, m, r) => {
                 for pat in l {
@@ -838,7 +810,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_name(f.ident.name);
                     self.hash_pat(f.pat);
                 }
-                e.hash(&mut self.s)
+                e.hash(&mut self.s);
             },
             PatKind::Tuple(pats, e) => {
                 for pat in pats {
@@ -864,6 +836,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             _ => {
                 for seg in path.segments {
                     self.hash_name(seg.ident.name);
+                    self.hash_generic_args(seg.args().args);
                 }
             },
         }
@@ -875,7 +848,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         match &b.kind {
             StmtKind::Local(local) => {
                 self.hash_pat(local.pat);
-                if let Some(ref init) = local.init {
+                if let Some(init) = local.init {
                     self.hash_expr(init);
                 }
             },
@@ -888,7 +861,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
     pub fn hash_guard(&mut self, g: &Guard<'_>) {
         match g {
-            Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
+            Guard::If(expr) | Guard::IfLet(_, expr) => {
                 self.hash_expr(expr);
             },
         }
@@ -921,25 +894,24 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_body(anon_const.body);
             },
             TyKind::Ptr(ref mut_ty) => {
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::Rptr(lifetime, ref mut_ty) => {
                 self.hash_lifetime(lifetime);
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::BareFn(bfn) => {
                 bfn.unsafety.hash(&mut self.s);
                 bfn.abi.hash(&mut self.s);
                 for arg in bfn.decl.inputs {
-                    self.hash_ty(&arg);
+                    self.hash_ty(arg);
                 }
+                std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
                 match bfn.decl.output {
-                    FnRetTy::DefaultReturn(_) => {
-                        ().hash(&mut self.s);
-                    },
-                    FnRetTy::Return(ref ty) => {
+                    FnRetTy::DefaultReturn(_) => {},
+                    FnRetTy::Return(ty) => {
                         self.hash_ty(ty);
                     },
                 }
@@ -950,24 +922,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_ty(ty);
                 }
             },
-            TyKind::Path(ref qpath) => match qpath {
-                QPath::Resolved(ref maybe_ty, ref path) => {
-                    if let Some(ref ty) = maybe_ty {
-                        self.hash_ty(ty);
-                    }
-                    for segment in path.segments {
-                        segment.ident.name.hash(&mut self.s);
-                        self.hash_generic_args(segment.args().args);
-                    }
-                },
-                QPath::TypeRelative(ref ty, ref segment) => {
-                    self.hash_ty(ty);
-                    segment.ident.name.hash(&mut self.s);
-                },
-                QPath::LangItem(lang_item, ..) => {
-                    lang_item.hash(&mut self.s);
-                },
-            },
+            TyKind::Path(ref qpath) => self.hash_qpath(qpath),
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
             },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 82250151aab..769836aaf18 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -63,7 +63,7 @@ use std::hash::BuildHasherDefault;
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -328,7 +328,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
 
 /// Checks if an expression references a variable of the given name.
 pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let [p] = path.segments {
             return p.ident.name == var;
         }
@@ -338,8 +338,8 @@ pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
 
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
-        QPath::TypeRelative(_, ref seg) => seg,
+        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
+        QPath::TypeRelative(_, seg) => seg,
         QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
     }
 }
@@ -367,8 +367,8 @@ pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx h
 
 pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.get(0),
-        QPath::TypeRelative(_, ref seg) => Some(seg),
+        QPath::Resolved(_, path) => path.segments.get(0),
+        QPath::TypeRelative(_, seg) => Some(seg),
         QPath::LangItem(..) => None,
     }
 }
@@ -388,8 +388,8 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
 /// ```
 pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
     match *path {
-        QPath::Resolved(_, ref path) => match_path(path, segments),
-        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+        QPath::Resolved(_, path) => match_path(path, segments),
+        QPath::TypeRelative(ty, segment) => match ty.kind {
             TyKind::Path(ref inner_path) => {
                 if let [prefix @ .., end] = segments {
                     if match_qpath(inner_path, prefix) {
@@ -457,7 +457,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 
 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let Res::Local(id) = path.res {
             return Some(id);
         }
@@ -661,13 +661,13 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
-        if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
+        if let ExprKind::MethodCall(path, _, args, _) = current.kind {
             if path.ident.name.as_str() == *method_name {
                 if args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
-                matched.push(&**args); // build up `matched` backwards
-                current = &args[0] // go to parent expression
+                matched.push(args); // build up `matched` backwards
+                current = &args[0]; // go to parent expression
             } else {
                 return None;
             }
@@ -712,7 +712,7 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
     match pat.kind {
         PatKind::Binding(.., ref spname, _) => Some(spname.name),
         PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
+        PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
         _ => None,
     }
 }
@@ -854,7 +854,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
             kind: ImplItemKind::Fn(_, eid),
             ..
         }) => match cx.tcx.hir().body(eid).value.kind {
-            ExprKind::Block(ref block, _) => Some(block),
+            ExprKind::Block(block, _) => Some(block),
             _ => None,
         },
         _ => None,
@@ -1028,7 +1028,7 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let ExprKind::Call(ref fun, _) = expr.kind {
+    if let ExprKind::Call(fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
@@ -1058,21 +1058,21 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     match pat.kind {
         PatKind::Wild => false,
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
-        PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
-        PatKind::Or(ref pats) => {
+        PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
-        PatKind::Struct(ref qpath, ref fields, _) => {
+        PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+        PatKind::Struct(ref qpath, fields, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
         },
-        PatKind::TupleStruct(ref qpath, ref pats, _) => {
+        PatKind::TupleStruct(ref qpath, pats, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Slice(ref head, ref middle, ref tail) => {
+        PatKind::Slice(head, ref middle, tail) => {
             match &cx.typeck_results().node_type(pat.hir_id).kind() {
                 rustc_ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
@@ -1094,9 +1094,9 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 /// the function once on the given pattern.
 pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
     if let PatKind::Or(pats) = pat.kind {
-        pats.iter().copied().for_each(f)
+        pats.iter().copied().for_each(f);
     } else {
-        f(pat)
+        f(pat);
     }
 }
 
@@ -1111,7 +1111,7 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 /// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 /// themselves.
 pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
-    while let ExprKind::Block(ref block, ..) = expr.kind {
+    while let ExprKind::Block(block, ..) = expr.kind {
         match (block.stmts.is_empty(), block.expr.as_ref()) {
             (true, Some(e)) => expr = e,
             _ => break,
@@ -1130,7 +1130,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if_chain! {
-        if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
+        if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
         if let Res::SelfTy(..) = path.res;
         then {
             return true
@@ -1148,7 +1148,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);
@@ -1167,7 +1167,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
         }
     }
 
-    if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
+    if let ExprKind::Match(_, arms, ref source) = expr.kind {
         // desugared from a `?` operator
         if let MatchSource::TryDesugar = *source {
             return Some(expr);
@@ -1254,12 +1254,12 @@ pub fn match_function_call<'tcx>(
     path: &[&str],
 ) -> Option<&'tcx [Expr<'tcx>]> {
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         if match_def_path(cx, fun_def_id, path);
         then {
-            return Some(&args)
+            return Some(args)
         }
     };
     None
@@ -1316,15 +1316,15 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     let mut conds = Vec::new();
     let mut blocks: Vec<&Block<'_>> = Vec::new();
 
-    while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
-        conds.push(&**cond);
-        if let ExprKind::Block(ref block, _) = then_expr.kind {
+    while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
+        conds.push(cond);
+        if let ExprKind::Block(block, _) = then_expr.kind {
             blocks.push(block);
         } else {
             panic!("ExprKind::If node is not an ExprKind::Block");
         }
 
-        if let Some(ref else_expr) = *else_expr {
+        if let Some(else_expr) = *else_expr {
             expr = else_expr;
         } else {
             break;
@@ -1333,8 +1333,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
 
     // final `else {..}`
     if !blocks.is_empty() {
-        if let ExprKind::Block(ref block, _) = expr.kind {
-            blocks.push(&**block);
+        if let ExprKind::Block(block, _) = expr.kind {
+            blocks.push(block);
         }
     }
 
@@ -1383,7 +1383,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 // check if expr is calling method or function with #[must_use] attribute
 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let did = match expr.kind {
-        ExprKind::Call(ref path, _) => if_chain! {
+        ExprKind::Call(path, _) => if_chain! {
             if let ExprKind::Path(ref qpath) = path.kind;
             if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
             then {
@@ -1396,7 +1396,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
+    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 }
 
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
@@ -1572,14 +1572,16 @@ where
     Hash: Fn(&T) -> u64,
     Eq: Fn(&T, &T) -> bool,
 {
-    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
-        return vec![(&exprs[0], &exprs[1])];
+    match exprs {
+        [a, b] if eq(a, b) => return vec![(a, b)],
+        _ if exprs.len() <= 2 => return vec![],
+        _ => {},
     }
 
     let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 
-    let mut map: FxHashMap<_, Vec<&_>> =
-        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+    let mut map: UnhashMap<u64, Vec<&_>> =
+        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 
     for expr in exprs {
         match map.entry(hash(expr)) {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 00df04c0144..4a9c4fd0276 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -26,4 +26,5 @@ msrv_aliases! {
     1,34,0 { TRY_FROM }
     1,30,0 { ITERATOR_FIND_MAP }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
+    1,16,0 { STR_REPEAT }
 }
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 268bc5b3205..546706d51d7 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -52,7 +52,7 @@ impl<'a> NumericLiteral<'a> {
 
     pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
         if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
-            let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
+            let (unsuffixed, suffix) = split_suffix(src, lit_kind);
             let float = matches!(lit_kind, LitKind::Float(..));
             Some(NumericLiteral::new(unsuffixed, suffix, float))
         } else {
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 5885cc83560..791688cd194 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         if self.abort {
             return;
         }
-        if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
+        if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
             if args.len() == 1 && match_var(&args[0], self.name) {
                 if seg.ident.name.as_str() == "capacity" {
                     self.abort = true;
@@ -79,5 +79,5 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
 }
 
 fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
-    get_pat_name(&arg.pat)
+    get_pat_name(arg.pat)
 }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index a08dcf19e5b..0e6ead675c2 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -255,7 +255,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t
         cursor = proj_base;
         match elem {
             ProjectionElem::Field(..) => {
-                let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty;
+                let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 0c950661757..efc0ec50fdc 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -2,7 +2,7 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite};
+use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{ast, token};
 use rustc_ast_pretty::pprust::token_kind_to_string;
@@ -10,7 +10,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, SyntaxContext};
 use std::borrow::Cow;
 use std::convert::TryInto;
 use std::fmt::Display;
@@ -90,6 +90,29 @@ impl<'a> Sugg<'a> {
         Self::hir_from_snippet(expr, snippet)
     }
 
+    /// Same as `hir`, but first walks the span up to the given context. This will result in the
+    /// macro call, rather then the expansion, if the span is from a child context. If the span is
+    /// not from a child context, it will be used directly instead.
+    ///
+    /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
+    /// node would result in `box []`. If given the context of the address of expression, this
+    /// function will correctly get a snippet of `vec![]`.
+    pub fn hir_with_context(
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        ctxt: SyntaxContext,
+        default: &'a str,
+        applicability: &mut Applicability,
+    ) -> Self {
+        let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
+
+        if in_macro {
+            Sugg::NonParen(snippet)
+        } else {
+            Self::hir_from_snippet(expr, snippet)
+        }
+    }
+
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
     fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
@@ -684,7 +707,7 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder
 
             if let Some(non_whitespace_offset) = non_whitespace_offset {
                 remove_span = remove_span
-                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
+                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
             }
         }
 
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index c36e215f184..a92d3be5d3c 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -142,21 +142,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
-        ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
-        ty::Slice(ref ty)
-        | ty::Array(ref ty, _)
-        | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
-        | ty::Ref(_, ref ty, _) => {
+        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+        ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
-        ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+        ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -166,7 +163,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Dynamic(binder, _) => {
             for predicate in binder.iter() {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -305,7 +302,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo
 /// Returns the base type for HIR references and pointers.
 pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
     match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
+        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
         _ => ty,
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 650b70c63af..2c55021ac88 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -59,7 +59,7 @@ impl<'tcx> MutVarsDelegate {
                 //FIXME: This causes false negatives. We can't get the `NodeId` from
                 //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
                 //`while`-body, not just the ones in the condition.
-                self.skip = true
+                self.skip = true;
             },
             _ => {},
         }
@@ -71,12 +71,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
 
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
         if let ty::BorrowKind::MutBorrow = bk {
-            self.update(&cmt)
+            self.update(cmt);
         }
     }
 
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
-        self.update(&cmt)
+        self.update(cmt);
     }
 
     fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index ecdc666b5f6..ce00106dd4d 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -87,7 +87,7 @@ where
         }
 
         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
-            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
         }
 
         fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
@@ -189,34 +189,21 @@ impl<'v> Visitor<'v> for LocalUsedVisitor<'v> {
     }
 }
 
+/// A type which can be visited.
 pub trait Visitable<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V);
+    /// Calls the corresponding `visit_*` function on the visitor.
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
-impl Visitable<'tcx> for &'tcx Expr<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_expr(self)
-    }
-}
-impl Visitable<'tcx> for &'tcx Block<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_block(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_stmt(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_body(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_arm(self)
-    }
+macro_rules! visitable_ref {
+    ($t:ident, $f:ident) => {
+        impl Visitable<'tcx> for &'tcx $t<'tcx> {
+            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+                visitor.$f(self);
+            }
+        }
+    };
 }
+visitable_ref!(Block, visit_block);
 
 /// Calls the given function for each break expression.
 pub fn visit_break_exprs<'tcx>(
@@ -232,7 +219,7 @@ pub fn visit_break_exprs<'tcx>(
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if let ExprKind::Break(dest, sub_expr) = e.kind {
-                self.0(e, dest, sub_expr)
+                self.0(e, dest, sub_expr);
             }
             walk_expr(self, e);
         }
@@ -264,7 +251,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
                     self.found = true;
                 }
             } else {
-                walk_expr(self, e)
+                walk_expr(self, e);
             }
         }
     }
diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md
index eaa6a9af277..e0af9bf0625 100644
--- a/src/tools/clippy/doc/release.md
+++ b/src/tools/clippy/doc/release.md
@@ -94,7 +94,7 @@ After finding the Clippy commit, it can be tagged with the release number.
 # Assuming the current directory corresponds to the Clippy repository
 $ git checkout $SHA
 $ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
-$ git push upstream master --tags   # `upstream` is the `rust-lang/rust-clippy` remote
+$ git push upstream rust-1.XX.0     # `upstream` is the `rust-lang/rust-clippy` remote
 ```
 
 After this, the release should be available on the Clippy [release page].
diff --git a/src/tools/clippy/mini-macro/Cargo.toml b/src/tools/clippy/mini-macro/Cargo.toml
deleted file mode 100644
index 0d95c86aef0..00000000000
--- a/src/tools/clippy/mini-macro/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-authors = ["The Rust Clippy Developers"]
-license = "MIT OR Apache-2.0"
-description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang/rust-clippy"
-edition = "2018"
-
-[lib]
-name = "clippy_mini_macro_test"
-proc-macro = true
-
-[dependencies]
diff --git a/src/tools/clippy/mini-macro/src/lib.rs b/src/tools/clippy/mini-macro/src/lib.rs
deleted file mode 100644
index 2b793589049..00000000000
--- a/src/tools/clippy/mini-macro/src/lib.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(proc_macro_quote)]
-#![deny(rust_2018_idioms)]
-// FIXME: Remove this attribute once the weird failure is gone.
-#![allow(unused_extern_crates)]
-extern crate proc_macro;
-
-use proc_macro::{quote, TokenStream};
-
-#[proc_macro_derive(ClippyMiniMacroTest)]
-/// # Panics
-///
-/// Panics if the macro derivation fails
-pub fn mini_macro(_: TokenStream) -> TokenStream {
-    quote!(
-        #[allow(unused)]
-        fn needless_take_by_value(s: String) {
-            println!("{}", s.len());
-        }
-        #[allow(unused)]
-        fn needless_loop(items: &[u8]) {
-            for i in 0..items.len() {
-                println!("{}", items[i]);
-            }
-        }
-        fn line_wrapper() {
-            println!("{}", line!());
-        }
-    )
-}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index cb8cb0978f6..e3863c46288 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-05-20"
+channel = "nightly-2021-06-03"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index ff2a7de5725..5f289918a7c 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -100,9 +100,9 @@ pub fn get_commit_date() -> Option<String> {
 }
 
 #[must_use]
-pub fn get_channel() -> Option<String> {
+pub fn get_channel() -> String {
     match env::var("CFG_RELEASE_CHANNEL") {
-        Ok(channel) => Some(channel),
+        Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
             match std::process::Command::new("rustc")
@@ -113,16 +113,16 @@ pub fn get_channel() -> Option<String> {
             {
                 Some(rustc_output) => {
                     if rustc_output.contains("beta") {
-                        Some(String::from("beta"))
+                        String::from("beta")
                     } else if rustc_output.contains("stable") {
-                        Some(String::from("stable"))
+                        String::from("stable")
                     } else {
                         // default to nightly if we fail to parse
-                        Some(String::from("nightly"))
+                        String::from("nightly")
                     }
                 },
                 // default to nightly
-                None => Some(String::from("nightly")),
+                None => String::from("nightly"),
             }
         },
     }
diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml
new file mode 100644
index 00000000000..5eb7ac03541
--- /dev/null
+++ b/src/tools/clippy/tests/clippy.toml
@@ -0,0 +1 @@
+# default config for tests, overrides clippy.toml at the project root
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index e1110721f6e..7d266a36bb6 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -4,8 +4,8 @@
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
 
-use std::env::{self, set_var, var};
-use std::ffi::OsStr;
+use std::env::{self, remove_var, set_var, var_os};
+use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
@@ -88,9 +88,11 @@ fn default_config() -> compiletest::Config {
     config
 }
 
-fn run_mode(cfg: &mut compiletest::Config) {
+fn run_ui(cfg: &mut compiletest::Config) {
     cfg.mode = TestMode::Ui;
     cfg.src_base = Path::new("tests").join("ui");
+    // use tests/clippy.toml
+    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
     compiletest::run_tests(cfg);
 }
 
@@ -114,7 +116,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
                 continue;
             }
             let dir_path = dir.path();
-            set_var("CARGO_MANIFEST_DIR", &dir_path);
+            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
             for file in fs::read_dir(&dir_path)? {
                 let file = file?;
                 let file_path = file.path();
@@ -145,9 +147,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
 
     let tests = compiletest::make_tests(config);
 
-    let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
     let res = run_tests(config, tests);
-    set_var("CARGO_MANIFEST_DIR", &manifest_dir);
     match res {
         Ok(true) => {},
         Ok(false) => panic!("Some tests failed"),
@@ -208,7 +208,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
                         Some("main.rs") => {},
                         _ => continue,
                     }
-                    set_var("CLIPPY_CONF_DIR", case.path());
+                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                     let paths = compiletest::common::TestPaths {
                         file: file_path,
                         base: config.src_base.clone(),
@@ -236,10 +236,8 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
     let tests = compiletest::make_tests(config);
 
     let current_dir = env::current_dir().unwrap();
-    let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
     let res = run_tests(config, &config.filters, tests);
     env::set_current_dir(current_dir).unwrap();
-    set_var("CLIPPY_CONF_DIR", conf_dir);
 
     match res {
         Ok(true) => {},
@@ -260,8 +258,32 @@ fn prepare_env() {
 fn compile_test() {
     prepare_env();
     let mut config = default_config();
-    run_mode(&mut config);
+    run_ui(&mut config);
     run_ui_toml(&mut config);
     run_ui_cargo(&mut config);
     run_internal_tests(&mut config);
 }
+
+/// Restores an env var on drop
+#[must_use]
+struct VarGuard {
+    key: &'static str,
+    value: Option<OsString>,
+}
+
+impl VarGuard {
+    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+        let value = var_os(key);
+        set_var(key, val);
+        Self { key, value }
+    }
+}
+
+impl Drop for VarGuard {
+    fn drop(&mut self) {
+        match self.value.as_deref() {
+            None => remove_var(self.key),
+            Some(value) => set_var(self.key, value),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 5d9f128753f..7de130c7dbe 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -179,8 +179,39 @@ fn dogfood_subprojects() {
 #[ignore]
 #[cfg(feature = "metadata-collector-lint")]
 fn run_metadata_collection_lint() {
+    use std::fs::File;
+    use std::time::SystemTime;
+
+    // Setup for validation
+    let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
+    let start_time = SystemTime::now();
+
+    // Run collection as is
     std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
     run_clippy_for_project("clippy_lints");
+
+    // Check if cargo caching got in the way
+    if let Ok(file) = File::open(metadata_output_path) {
+        if let Ok(metadata) = file.metadata() {
+            if let Ok(last_modification) = metadata.modified() {
+                if last_modification > start_time {
+                    // The output file has been modified. Most likely by a hungry
+                    // metadata collection monster. So We'll return.
+                    return;
+                }
+            }
+        }
+    }
+
+    // Force cargo to invalidate the caches
+    filetime::set_file_mtime(
+        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
+        filetime::FileTime::now(),
+    )
+    .unwrap();
+
+    // Running the collection again
+    run_clippy_for_project("clippy_lints");
 }
 
 fn run_clippy_for_project(project: &str) {
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index d83080b69f5..a7be00426c4 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index aebeaf34679..4b7b7fec78f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -53,3 +53,22 @@ pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream {
         }
     }
 }
+
+#[proc_macro_derive(ClippyMiniMacroTest)]
+pub fn mini_macro(_: TokenStream) -> TokenStream {
+    quote!(
+        #[allow(unused)]
+        fn needless_take_by_value(s: String) {
+            println!("{}", s.len());
+        }
+        #[allow(unused)]
+        fn needless_loop(items: &[u8]) {
+            for i in 0..items.len() {
+                println!("{}", items[i]);
+            }
+        }
+        fn line_wrapper() {
+            println!("{}", line!());
+        }
+    )
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs
new file mode 100644
index 00000000000..780797e3c6a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs
@@ -0,0 +1,14 @@
+pub fn warn<T>(_: T) {}
+
+macro_rules! define_macro {
+    ($d:tt $lower:ident $upper:ident) => {
+        #[macro_export]
+        macro_rules! $upper {
+            ($arg:tt) => {
+                $crate::$lower($arg)
+            };
+        }
+    };
+}
+
+define_macro! {$ warn  WARNING}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs
new file mode 100644
index 00000000000..57ab6ca14f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs
@@ -0,0 +1,12 @@
+// aux-build:ice-7272-aux.rs
+
+#![allow(clippy::no_effect)]
+
+extern crate ice_7272_aux;
+
+use ice_7272_aux::*;
+
+pub fn main() {
+    || WARNING!("Style changed!");
+    || "}{";
+}
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
deleted file mode 100644
index c7468493380..00000000000
--- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#[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/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 2a948d60b10..cba7666c2d8 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
 
-pub struct A;
+struct A;
 
 impl A {
     pub fn as_ref(self) -> &'static str {
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index dbf0b03af76..4ba9f0c1fcf 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -12,5 +12,7 @@
 #[warn(clippy::unknown_clippy_lints)]
 #[warn(clippy::find_map)]
 #[warn(clippy::filter_map)]
+#[warn(clippy::pub_enum_variant_names)]
+#[warn(clippy::wrong_pub_self_convention)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index e5de839dbc5..03c9f438891 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -84,5 +84,17 @@ error: lint `clippy::filter_map` has been removed: this lint has been replaced b
 LL | #[warn(clippy::filter_map)]
    |        ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items
+  --> $DIR/deprecated.rs:15:8
+   |
+LL | #[warn(clippy::pub_enum_variant_names)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items
+  --> $DIR/deprecated.rs:16:8
+   |
+LL | #[warn(clippy::wrong_pub_self_convention)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
index 4fefc0b43f1..083f5143e6e 100644
--- a/src/tools/clippy/tests/ui/enum_variants.rs
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -1,5 +1,4 @@
-#![feature(non_ascii_idents)]
-#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![warn(clippy::enum_variant_names)]
 #![allow(non_camel_case_types, clippy::upper_case_acronyms)]
 
 enum FakeCallType {
@@ -97,8 +96,8 @@ pub enum PubSeall {
     WithOut,
 }
 
-#[allow(clippy::pub_enum_variant_names)]
-mod allowed {
+#[allow(clippy::enum_variant_names)]
+pub mod allowed {
     pub enum PubAllowed {
         SomeThis,
         SomeThat,
diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr
index ab7fff4507a..447fbb9e1bf 100644
--- a/src/tools/clippy/tests/ui/enum_variants.stderr
+++ b/src/tools/clippy/tests/ui/enum_variants.stderr
@@ -1,5 +1,5 @@
 error: variant name ends with the enum's name
-  --> $DIR/enum_variants.rs:16:5
+  --> $DIR/enum_variants.rs:15:5
    |
 LL |     cFoo,
    |     ^^^^
@@ -7,25 +7,25 @@ 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
+  --> $DIR/enum_variants.rs:26:5
    |
 LL |     FoodGood,
    |     ^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:28:5
+  --> $DIR/enum_variants.rs:27:5
    |
 LL |     FoodMiddle,
    |     ^^^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:29:5
+  --> $DIR/enum_variants.rs:28:5
    |
 LL |     FoodBad,
    |     ^^^^^^^
 
 error: all variants have the same prefix: `Food`
-  --> $DIR/enum_variants.rs:26:1
+  --> $DIR/enum_variants.rs:25:1
    |
 LL | / enum Food {
 LL | |     FoodGood,
@@ -37,7 +37,7 @@ 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
+  --> $DIR/enum_variants.rs:35:1
    |
 LL | / enum BadCallType {
 LL | |     CallTypeCall,
@@ -49,7 +49,7 @@ 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
+  --> $DIR/enum_variants.rs:47:1
    |
 LL | / enum Consts {
 LL | |     ConstantInt,
@@ -61,7 +61,7 @@ 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
+  --> $DIR/enum_variants.rs:81:1
    |
 LL | / enum Seallll {
 LL | |     WithOutCake,
@@ -73,7 +73,7 @@ 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
+  --> $DIR/enum_variants.rs:87:1
    |
 LL | / enum NonCaps {
 LL | |     Prefixçš„,
@@ -84,21 +84,8 @@ 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: all variants have the same postfix: `IData`
-  --> $DIR/enum_variants.rs:137:1
+  --> $DIR/enum_variants.rs:136:1
    |
 LL | / enum IDataRequest {
 LL | |     PutIData(String),
@@ -110,7 +97,7 @@ LL | | }
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same postfix: `HIData`
-  --> $DIR/enum_variants.rs:143:1
+  --> $DIR/enum_variants.rs:142:1
    |
 LL | / enum HIDataRequest {
 LL | |     PutHIData(String),
@@ -121,5 +108,5 @@ LL | | }
    |
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 2be2283e3fd..9e752311c67 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -48,6 +48,9 @@ fn main() {
     // 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) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index f0373f9ccf6..44be4628cbd 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -48,6 +48,9 @@ fn main() {
     // 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) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 57ed6527966..8795d3b42c6 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -33,7 +33,7 @@ LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> $DIR/eta.rs:89:51
+  --> $DIR/eta.rs:92:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,43 +41,43 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
 
 error: redundant closure
-  --> $DIR/eta.rs:91:51
+  --> $DIR/eta.rs:94:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> $DIR/eta.rs:94:42
+  --> $DIR/eta.rs:97:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> $DIR/eta.rs:99:29
+  --> $DIR/eta.rs:102:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> $DIR/eta.rs:101:27
+  --> $DIR/eta.rs:104:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:104:65
+  --> $DIR/eta.rs:107:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:187:27
+  --> $DIR/eta.rs:190:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> $DIR/eta.rs:192:27
+  --> $DIR/eta.rs:195:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
index b5f548810e6..12db43b5343 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        iter.into_iter().copied().collect::<Self>()
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = iter_expr.collect::<Vec<_>>();
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
index b842b5451d1..f5ec190e0cd 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = Vec::from_iter(iter_expr);
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
index 434734c9a21..8f08ac8c3ff 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
@@ -1,88 +1,94 @@
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:11:13
+  --> $DIR/from_iter_instead_of_collect.rs:19:9
    |
-LL |     let _ = Vec::from_iter(iter_expr);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+LL |         <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
    |
    = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:13:13
+  --> $DIR/from_iter_instead_of_collect.rs:25:13
+   |
+LL |     let _ = Vec::from_iter(iter_expr);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+
+error: usage of `FromIterator::from_iter`
+  --> $DIR/from_iter_instead_of_collect.rs:27:13
    |
 LL |     let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:18:19
+  --> $DIR/from_iter_instead_of_collect.rs:32:19
    |
 LL |     assert_eq!(a, Vec::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:19:19
+  --> $DIR/from_iter_instead_of_collect.rs:33:19
    |
 LL |     assert_eq!(a, Vec::<i32>::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:21:17
+  --> $DIR/from_iter_instead_of_collect.rs:35:17
    |
 LL |     let mut b = VecDeque::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:24:17
+  --> $DIR/from_iter_instead_of_collect.rs:38:17
    |
 LL |     let mut b = VecDeque::<i32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:29:21
+  --> $DIR/from_iter_instead_of_collect.rs:43:21
    |
 LL |         let mut b = collections::VecDeque::<i32>::from_iter(0..3);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:34:14
+  --> $DIR/from_iter_instead_of_collect.rs:48:14
    |
 LL |     let bm = BTreeMap::from_iter(values.iter().cloned());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:35:19
+  --> $DIR/from_iter_instead_of_collect.rs:49:19
    |
 LL |     let mut bar = BTreeMap::from_iter(bm.range(0..2));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:38:19
+  --> $DIR/from_iter_instead_of_collect.rs:52:19
    |
 LL |     let mut bts = BTreeSet::from_iter(0..3);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:42:17
+  --> $DIR/from_iter_instead_of_collect.rs:56:17
    |
 LL |         let _ = collections::BTreeSet::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:43:17
+  --> $DIR/from_iter_instead_of_collect.rs:57:17
    |
 LL |         let _ = collections::BTreeSet::<u32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:46:15
+  --> $DIR/from_iter_instead_of_collect.rs:60:15
    |
 LL |     for _i in Vec::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:47:15
+  --> $DIR/from_iter_instead_of_collect.rs:61:15
    |
 LL |     for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
index 0a86568b18d..a2b8c2a384b 100644
--- a/src/tools/clippy/tests/ui/functions.stderr
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -30,7 +30,7 @@ error: this function has too many arguments (8/7)
 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`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:63:34
    |
 LL |         println!("{}", unsafe { *p });
@@ -38,49 +38,49 @@ 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference 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`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:89:33
    |
 LL |         unsafe { std::ptr::read(p) };
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed
index 51c66a46368..70d49d9f2c4 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.fixed
+++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs
index 2011129bc94..68370023861 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.rs
+++ b/src/tools/clippy/tests/ui/macro_use_imports.rs
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     #[macro_use]
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr
index f8c86c8d917..49314b7506d 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.stderr
+++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr
@@ -1,5 +1,5 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:18:5
+  --> $DIR/macro_use_imports.rs:19:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
@@ -7,22 +7,22 @@ LL |     #[macro_use]
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:20:5
+  --> $DIR/macro_use_imports.rs:25:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:22:5
+  --> $DIR/macro_use_imports.rs:21:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:24:5
+  --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
new file mode 100644
index 00000000000..dc140257f32
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = "test".repeat(10);
+    let _: String = "x".repeat(10);
+    let _: String = "'".repeat(10);
+    let _: String = "\"".repeat(10);
+
+    let x = "test";
+    let count = 10;
+    let _ = x.repeat(count + 2);
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = (*x).repeat(count);
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = x.repeat(count);
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = Cow::Borrowed("test").repeat(count);
+
+    let x = "x".to_owned();
+    let _: String = x.repeat(count);
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = "test".repeat(10);
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs
new file mode 100644
index 00000000000..0d69c989b2e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = std::iter::repeat("test").take(10).collect();
+    let _: String = std::iter::repeat('x').take(10).collect();
+    let _: String = std::iter::repeat('\'').take(10).collect();
+    let _: String = std::iter::repeat('"').take(10).collect();
+
+    let x = "test";
+    let count = 10;
+    let _ = repeat(x).take(count + 2).collect::<String>();
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = repeat(*x).take(count).collect();
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = repeat(x).take(count).collect();
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+
+    let x = "x".to_owned();
+    let _: String = repeat(x).take(count).collect();
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
new file mode 100644
index 00000000000..c6511689716
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
@@ -0,0 +1,64 @@
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:10:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+   |
+   = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:11:21
+   |
+LL |     let _: String = std::iter::repeat('x').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:12:21
+   |
+LL |     let _: String = std::iter::repeat('/'').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:13:21
+   |
+LL |     let _: String = std::iter::repeat('"').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:17:13
+   |
+LL |     let _ = repeat(x).take(count + 2).collect::<String>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:26:21
+   |
+LL |     let _: String = repeat(*x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:35:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:47:21
+   |
+LL |     let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:50:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:65:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs
index 57af84dcdf4..bfa9ef01b0e 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.rs
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.rs
@@ -67,7 +67,10 @@ impl PubFoo {
     pub fn foo() {}
     /// dox
     pub fn foo1() {}
-    fn foo2() {}
+    #[must_use = "yep"]
+    fn foo2() -> u32 {
+        1
+    }
     #[allow(clippy::missing_docs_in_private_items)]
     pub fn foo3() {}
 }
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
index 7e10404ca00..d33d512475b 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
@@ -94,10 +94,12 @@ LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:70:5
+  --> $DIR/missing-doc-impl.rs:71:5
    |
-LL |     fn foo2() {}
-   |     ^^^^^^^^^^^^
+LL | /     fn foo2() -> u32 {
+LL | |         1
+LL | |     }
+   | |_____^
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs
index 669bf01a84c..f5908cb5701 100644
--- a/src/tools/clippy/tests/ui/module_name_repetitions.rs
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs
@@ -15,12 +15,4 @@ mod foo {
     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/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 5ae4a0e79b9..a87171dc3f2 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -18,7 +18,6 @@ fn main() {
     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 => {
@@ -43,19 +42,3 @@ 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
index 1e281316c8a..059dc8ceac3 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -18,7 +18,6 @@ fn main() {
     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 => {
@@ -43,19 +42,3 @@ 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
index bea4b41b803..6eddf26db06 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -6,23 +6,11 @@ LL |     let c = x(&&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 (`&i32`) that is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:28:15
+  --> $DIR/needless_borrow.rs:27: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
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
new file mode 100644
index 00000000000..f0926220755
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
@@ -0,0 +1,151 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::needless_borrow)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m1 {
+    ($e:expr) => {
+        f1($e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+macro_rules! if_chain {
+    (if $e:expr; $($rest:tt)*) => {
+        if $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (if let $p:pat = $e:expr; $($rest:tt)*) => {
+        if let $p = $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (then $b:block) => {
+        $b
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, reference to a String.
+    let _: &String = match Some(x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, reference to a &mut String
+    let _: &&mut String = match Some(&mut x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, the pattern is from a macro
+    let _: &String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String.
+    let _: &String = match Some(&x) {
+        Some(ref x) => *x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m1!(x),
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &String = x;
+    };
+
+    // Err, reference to a &String
+    let (ref y,) = (&x,);
+    let _: &String = *y;
+
+    let y = &&x;
+    // Ok, different y
+    let _: &String = *y;
+
+    let x = (0, 0);
+    // Err, reference to a &u32. Don't suggest adding a reference to the field access.
+    let _: u32 = match Some(&x) {
+        Some(ref x) => x.0,
+        None => return,
+    };
+
+    enum E {
+        A(&'static u32),
+        B(&'static u32),
+    }
+    // Err, reference to &u32.
+    let _: &u32 = match E::A(&0) {
+        E::A(ref x) | E::B(ref x) => *x,
+    };
+
+    // Err, reference to &String.
+    if_chain! {
+        if true;
+        if let Some(ref x) = Some(&String::new());
+        then {
+            f1(x);
+        }
+    }
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = *x;
+    }
+}
+
+// Ok - used to error due to rustc bug
+#[allow(dead_code)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
new file mode 100644
index 00000000000..32913d59f7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
@@ -0,0 +1,112 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:60:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^ help: try this: `x`
+   |
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:66:14
+   |
+LL |         Some(ref x) => *x,
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => x,
+   |              ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:72:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:82:14
+   |
+LL |         Some(ref x) => m1!(x),
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:87:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:92:10
+   |
+LL |     let (ref y,) = (&x,);
+   |          ^^^^^
+   |
+help: try this
+   |
+LL |     let (y,) = (&x,);
+LL |     let _: &String = y;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:102:14
+   |
+LL |         Some(ref x) => x.0,
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:112:14
+   |
+LL |         E::A(ref x) | E::B(ref x) => *x,
+   |              ^^^^^         ^^^^^
+   |
+help: try this
+   |
+LL |         E::A(x) | E::B(x) => x,
+   |              ^         ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:118:21
+   |
+LL |         if let Some(ref x) = Some(&String::new());
+   |                     ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:126:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &String = x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:133:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:141:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &String = x;
+   |
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
index 2458bf1e490..2c94235b8f5 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
@@ -1,4 +1,4 @@
-use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
+use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
 
 fn main() {
     let sample = [1; 5];
@@ -75,3 +75,9 @@ mod issue7110 {
         buffer.len()
     }
 }
+
+fn allow_test() {
+    #[allow(clippy::needless_collect)]
+    let v = [1].iter().collect::<Vec<_>>();
+    v.into_iter().collect::<HashSet<_>>();
+}
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index 8fbfcb79860..7ec845adfaa 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -91,6 +91,9 @@ fn main() {
     let s: String = "foo".into();
     FooString { s: s };
 
+    #[allow(clippy::no_effect)]
+    0;
+
     // Do not warn
     get_number();
     unsafe { unsafe_fn() };
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
new file mode 100644
index 00000000000..c7235e1c221
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
@@ -0,0 +1,76 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::ref_binding_to_reference)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m2 {
+    ($e:expr) => {
+        f1(*$e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, the pattern is from a macro
+    let _: &&String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m2!(x),
+        None => return,
+    }
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &&String = x;
+    };
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &&String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
new file mode 100644
index 00000000000..00aeff4fefa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
@@ -0,0 +1,88 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:31:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^
+   |
+   = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
+help: try this
+   |
+LL |         Some(x) => &x,
+   |              ^     ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:37:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+LL |             &x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:47:14
+   |
+LL |         Some(ref x) => m2!(x),
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => m2!(&x),
+   |              ^         ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:52:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^
+   |
+help: try this
+   |
+LL |     let _ = |&x: &&String| {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:58:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &&String = &x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:65:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:73:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs
index 5981980988b..2b1bc1f4859 100644
--- a/src/tools/clippy/tests/ui/similar_names.rs
+++ b/src/tools/clippy/tests/ui/similar_names.rs
@@ -72,6 +72,10 @@ fn main() {
     let rx1: i32;
     let tx_cake: i32;
     let rx_cake: i32;
+
+    // names often used in win32 code (for example WindowProc)
+    let wparam: i32;
+    let lparam: i32;
 }
 
 fn foo() {
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
index 0256f126a94..a7eb2be0778 100644
--- a/src/tools/clippy/tests/ui/similar_names.stderr
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -92,13 +92,13 @@ LL |     let parsee: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:81:16
+  --> $DIR/similar_names.rs:85:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:80:16
+  --> $DIR/similar_names.rs:84:16
    |
 LL |         apple: spring,
    |                ^^^^^^
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index fcbe9af9f56..1abd2b7883d 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit('x');
     x.split_terminator('x');
     x.rsplit_terminator('x');
-    x.splitn(0, 'x');
-    x.rsplitn(0, 'x');
+    x.splitn(2, 'x');
+    x.rsplitn(2, 'x');
     x.matches('x');
     x.rmatches('x');
     x.match_indices('x');
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index b8bc20f4070..e662bf34be2 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit("x");
     x.split_terminator("x");
     x.rsplit_terminator("x");
-    x.splitn(0, "x");
-    x.rsplitn(0, "x");
+    x.splitn(2, "x");
+    x.rsplitn(2, "x");
     x.matches("x");
     x.rmatches("x");
     x.match_indices("x");
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index 6d94d8a34e3..22d4b2d460f 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -75,13 +75,13 @@ LL |     x.rsplit_terminator("x");
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:28:17
    |
-LL |     x.splitn(0, "x");
+LL |     x.splitn(2, "x");
    |                 ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:29:18
    |
-LL |     x.rsplitn(0, "x");
+LL |     x.rsplitn(2, "x");
    |                  ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs
new file mode 100644
index 00000000000..a21d94cf20b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs
@@ -0,0 +1,20 @@
+#![warn(clippy::suspicious_splitn)]
+
+fn main() {
+    let _ = "a,b,c".splitn(3, ',');
+    let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1);
+    let _ = "".splitn(0, ',');
+    let _ = [].splitn(0, |&x: &u32| x == 1);
+
+    let _ = "a,b".splitn(0, ',');
+    let _ = "a,b".rsplitn(0, ',');
+    let _ = "a,b".splitn(1, ',');
+    let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+    let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+
+    const X: usize = 0;
+    let _ = "a,b".splitn(X + 1, ',');
+    let _ = "a,b".splitn(X, ',');
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
new file mode 100644
index 00000000000..b6220ae2393
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
@@ -0,0 +1,75 @@
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:9:13
+   |
+LL |     let _ = "a,b".splitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
+   = note: the resulting iterator will always return `None`
+
+error: `rsplitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:10:13
+   |
+LL |     let _ = "a,b".rsplitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:11:13
+   |
+LL |     let _ = "a,b".splitn(1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:12:13
+   |
+LL |     let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn_mut` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:13:13
+   |
+LL |     let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:14:13
+   |
+LL |     let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `rsplitn_mut` called with `1` split
+  --> $DIR/suspicious_splitn.rs:15:13
+   |
+LL |     let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:18:13
+   |
+LL |     let _ = "a,b".splitn(X + 1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:19:13
+   |
+LL |     let _ = "a,b".splitn(X, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: aborting due to 9 previous errors
+
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
index ccc3cdb2b74..2b0005bbff1 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -89,12 +89,6 @@ 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: 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:108:21
    |
 LL |     fn foo_never(x: &i32) {
@@ -106,5 +100,5 @@ error: this argument (N byte) is passed by reference, but would be more efficien
 LL |     fn foo(x: &i32) {
    |               ^^^^ help: consider passing by value instead: `i32`
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs
index 54f22e3ee6a..63648ef5826 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs
@@ -65,7 +65,7 @@ fn func10() -> Option<()> {
     unimplemented!()
 }
 
-struct A;
+pub struct A;
 
 impl A {
     // should not be linted
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
index 3c422cc4fee..f0c2ba7ccdf 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
index 09608661e0e..f44880b4147 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
index a0c0be7a9d1..ab2f75e0c56 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
@@ -1,5 +1,5 @@
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:23:18
+  --> $DIR/unseparated_prefix_literals.rs:24:18
    |
 LL |     let _fail1 = 1234i32;
    |                  ^^^^^^^ help: add an underscore: `1234_i32`
@@ -7,43 +7,43 @@ LL |     let _fail1 = 1234i32;
    = 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
+  --> $DIR/unseparated_prefix_literals.rs:25: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
+  --> $DIR/unseparated_prefix_literals.rs:26: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
+  --> $DIR/unseparated_prefix_literals.rs:27: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
+  --> $DIR/unseparated_prefix_literals.rs:28: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
+  --> $DIR/unseparated_prefix_literals.rs:32: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
+  --> $DIR/unseparated_prefix_literals.rs:33: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
+  --> $DIR/unseparated_prefix_literals.rs:16:9
    |
 LL |         42usize
    |         ^^^^^^^ help: add an underscore: `42_usize`
@@ -54,7 +54,7 @@ LL |     let _ = lit_from_macro!();
    = note: this error originates in the macro `lit_from_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
+  --> $DIR/unseparated_prefix_literals.rs:41:16
    |
 LL |     assert_eq!(4897u32, 32223);
    |                ^^^^^^^ help: add an underscore: `4897_u32`
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs
index cdfbdb8b0db..151dd0c27d5 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
index 29f5ba82695..ce23317abf6 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:18:17
+  --> $DIR/wrong_self_convention.rs:17:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -8,7 +8,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:24:21
+  --> $DIR/wrong_self_convention.rs:23:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -16,7 +16,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:36:15
+  --> $DIR/wrong_self_convention.rs:35:15
    |
 LL |     fn as_i32(self) {}
    |               ^^^^
@@ -24,7 +24,7 @@ LL |     fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:38:17
+  --> $DIR/wrong_self_convention.rs:37:17
    |
 LL |     fn into_i32(&self) {}
    |                 ^^^^^
@@ -32,7 +32,7 @@ LL |     fn into_i32(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:40:15
+  --> $DIR/wrong_self_convention.rs:39:15
    |
 LL |     fn is_i32(self) {}
    |               ^^^^
@@ -40,7 +40,7 @@ LL |     fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:42:15
+  --> $DIR/wrong_self_convention.rs:41:15
    |
 LL |     fn to_i32(self) {}
    |               ^^^^
@@ -48,7 +48,7 @@ LL |     fn to_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:44:17
+  --> $DIR/wrong_self_convention.rs:43:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -56,7 +56,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:46:19
+  --> $DIR/wrong_self_convention.rs:45:19
    |
 LL |     pub fn as_i64(self) {}
    |                   ^^^^
@@ -64,7 +64,7 @@ LL |     pub fn as_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:47:21
+  --> $DIR/wrong_self_convention.rs:46:21
    |
 LL |     pub fn into_i64(&self) {}
    |                     ^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn into_i64(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:48:19
+  --> $DIR/wrong_self_convention.rs:47:19
    |
 LL |     pub fn is_i64(self) {}
    |                   ^^^^
@@ -80,7 +80,7 @@ LL |     pub fn is_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:49:19
+  --> $DIR/wrong_self_convention.rs:48:19
    |
 LL |     pub fn to_i64(self) {}
    |                   ^^^^
@@ -88,7 +88,7 @@ LL |     pub fn to_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:50:21
+  --> $DIR/wrong_self_convention.rs:49:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -96,7 +96,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:95:19
+  --> $DIR/wrong_self_convention.rs:94:19
    |
 LL |         fn as_i32(self) {}
    |                   ^^^^
@@ -104,7 +104,7 @@ LL |         fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:98:25
+  --> $DIR/wrong_self_convention.rs:97:25
    |
 LL |         fn into_i32_ref(&self) {}
    |                         ^^^^^
@@ -112,7 +112,7 @@ LL |         fn into_i32_ref(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:100:19
+  --> $DIR/wrong_self_convention.rs:99:19
    |
 LL |         fn is_i32(self) {}
    |                   ^^^^
@@ -120,7 +120,7 @@ LL |         fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:104:21
+  --> $DIR/wrong_self_convention.rs:103:21
    |
 LL |         fn from_i32(self) {}
    |                     ^^^^
@@ -128,7 +128,7 @@ LL |         fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:119:19
+  --> $DIR/wrong_self_convention.rs:118:19
    |
 LL |         fn as_i32(self);
    |                   ^^^^
@@ -136,7 +136,7 @@ LL |         fn as_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:122:25
+  --> $DIR/wrong_self_convention.rs:121:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -144,7 +144,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:124:19
+  --> $DIR/wrong_self_convention.rs:123:19
    |
 LL |         fn is_i32(self);
    |                   ^^^^
@@ -152,7 +152,7 @@ LL |         fn is_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:128:21
+  --> $DIR/wrong_self_convention.rs:127:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -160,7 +160,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:146:25
+  --> $DIR/wrong_self_convention.rs:145:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -168,7 +168,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:152:21
+  --> $DIR/wrong_self_convention.rs:151:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -176,7 +176,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:176:22
+  --> $DIR/wrong_self_convention.rs:175:22
    |
 LL |         fn to_u64_v2(&self) -> u64 {
    |                      ^^^^^
@@ -184,7 +184,7 @@ LL |         fn to_u64_v2(&self) -> u64 {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:185:19
+  --> $DIR/wrong_self_convention.rs:184:19
    |
 LL |         fn to_u64(self) -> u64 {
    |                   ^^^^
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
index 3a72174d03d..501bc1e6a85 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
index d2d74ce099e..0e0d066d656 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:56:29
+  --> $DIR/wrong_self_convention2.rs:55:29
    |
 LL |         pub fn from_be_self(self) -> Self {
    |                             ^^^^
@@ -8,7 +8,7 @@ LL |         pub fn from_be_self(self) -> Self {
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:65:25
+  --> $DIR/wrong_self_convention2.rs:64:25
    |
 LL |         fn from_be_self(self) -> Self;
    |                         ^^^^
diff --git a/src/tools/clippy/util/cov.sh b/src/tools/clippy/util/cov.sh
deleted file mode 100755
index 3f9a6b06f72..00000000000
--- a/src/tools/clippy/util/cov.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/bash
-
-# This run `kcov` on Clippy. The coverage report will be at
-# `./target/cov/index.html`.
-# `compile-test` is special. `kcov` does not work directly on it so these files
-# are compiled manually.
-
-tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;)
-tmpdir=$(mktemp -d)
-
-cargo test --no-run --verbose
-
-for t in $tests; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/$t" \
-    cargo test --test "$t"
-done
-
-for t in ./tests/compile-fail/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/compile-fail-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-for t in ./tests/run-pass/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/run-pass-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-kcov --verify --merge target/cov "$tmpdir"/*