about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--CONTRIBUTING.md6
-rw-r--r--README.md2
-rw-r--r--clippy_dev/src/ra_setup.rs4
-rw-r--r--clippy_lints/Cargo.toml2
-rw-r--r--clippy_lints/src/atomic_ordering.rs106
-rw-r--r--clippy_lints/src/await_holding_lock.rs2
-rw-r--r--clippy_lints/src/bit_mask.rs2
-rw-r--r--clippy_lints/src/bytecount.rs7
-rw-r--r--clippy_lints/src/consts.rs4
-rw-r--r--clippy_lints/src/create_dir.rs51
-rw-r--r--clippy_lints/src/disallowed_method.rs73
-rw-r--r--clippy_lints/src/doc.rs2
-rw-r--r--clippy_lints/src/duration_subsec.rs4
-rw-r--r--clippy_lints/src/entry.rs4
-rw-r--r--clippy_lints/src/enum_variants.rs4
-rw-r--r--clippy_lints/src/fallible_impl_from.rs6
-rw-r--r--clippy_lints/src/format.rs4
-rw-r--r--clippy_lints/src/indexing_slicing.rs2
-rw-r--r--clippy_lints/src/inherent_to_string.rs4
-rw-r--r--clippy_lints/src/len_zero.rs4
-rw-r--r--clippy_lints/src/lib.rs34
-rw-r--r--clippy_lints/src/loops.rs107
-rw-r--r--clippy_lints/src/manual_non_exhaustive.rs4
-rw-r--r--clippy_lints/src/manual_strip.rs245
-rw-r--r--clippy_lints/src/map_err_ignore.rs147
-rw-r--r--clippy_lints/src/map_unit_fn.rs6
-rw-r--r--clippy_lints/src/match_on_vec_items.rs5
-rw-r--r--clippy_lints/src/matches.rs84
-rw-r--r--clippy_lints/src/methods/bind_instead_of_map.rs21
-rw-r--r--clippy_lints/src/methods/mod.rs88
-rw-r--r--clippy_lints/src/methods/unnecessary_lazy_eval.rs76
-rw-r--r--clippy_lints/src/misc.rs26
-rw-r--r--clippy_lints/src/misc_early.rs6
-rw-r--r--clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--clippy_lints/src/mut_key.rs10
-rw-r--r--clippy_lints/src/needless_arbitrary_self_type.rs30
-rw-r--r--clippy_lints/src/non_copy_const.rs95
-rw-r--r--clippy_lints/src/open_options.rs6
-rw-r--r--clippy_lints/src/option_if_let_else.rs37
-rw-r--r--clippy_lints/src/panic_in_result_fn.rs90
-rw-r--r--clippy_lints/src/path_buf_push_overwrite.rs4
-rw-r--r--clippy_lints/src/redundant_clone.rs23
-rw-r--r--clippy_lints/src/repeat_once.rs4
-rw-r--r--clippy_lints/src/shadow.rs5
-rw-r--r--clippy_lints/src/single_component_path_imports.rs2
-rw-r--r--clippy_lints/src/strings.rs4
-rw-r--r--clippy_lints/src/swap.rs3
-rw-r--r--clippy_lints/src/temporary_assignment.rs11
-rw-r--r--clippy_lints/src/types.rs275
-rw-r--r--clippy_lints/src/unnecessary_sort_by.rs13
-rw-r--r--clippy_lints/src/unwrap_in_result.rs6
-rw-r--r--clippy_lints/src/useless_conversion.rs10
-rw-r--r--clippy_lints/src/utils/ast_utils.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/utils/diagnostics.rs9
-rw-r--r--clippy_lints/src/utils/eager_or_lazy.rs128
-rw-r--r--clippy_lints/src/utils/internal_lints.rs119
-rw-r--r--clippy_lints/src/utils/mod.rs120
-rw-r--r--clippy_lints/src/utils/paths.rs7
-rw-r--r--clippy_lints/src/utils/qualify_min_const_fn.rs347
-rw-r--r--clippy_lints/src/utils/sugg.rs2
-rw-r--r--clippy_lints/src/utils/usage.rs66
-rw-r--r--clippy_lints/src/write.rs23
-rw-r--r--clippy_workspace_tests/build.rs7
-rw-r--r--doc/adding_lints.md4
-rw-r--r--doc/common_tools_writing_lints.md2
-rw-r--r--src/driver.rs4
-rw-r--r--src/lintlist/mod.rs46
-rw-r--r--tests/compile-test.rs2
-rw-r--r--tests/ui-toml/toml_disallowed_method/clippy.toml1
-rw-r--r--tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs13
-rw-r--r--tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr16
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--tests/ui/atomic_ordering_exchange.rs45
-rw-r--r--tests/ui/atomic_ordering_exchange.stderr131
-rw-r--r--tests/ui/atomic_ordering_exchange_weak.rs47
-rw-r--r--tests/ui/atomic_ordering_exchange_weak.stderr131
-rw-r--r--tests/ui/atomic_ordering_fetch_update.rs45
-rw-r--r--tests/ui/atomic_ordering_fetch_update.stderr131
-rw-r--r--tests/ui/auxiliary/proc_macro_attr.rs62
-rw-r--r--tests/ui/auxiliary/proc_macro_derive.rs1
-rw-r--r--tests/ui/borrow_interior_mutable_const.rs21
-rw-r--r--tests/ui/borrow_interior_mutable_const.stderr44
-rw-r--r--tests/ui/crashes/associated-constant-ice.rs2
-rw-r--r--tests/ui/crashes/auxiliary/proc_macro_crash.rs1
-rw-r--r--tests/ui/crashes/cc_seme.rs2
-rw-r--r--tests/ui/crashes/enum-glob-import-crate.rs2
-rw-r--r--tests/ui/crashes/ice-1588.rs2
-rw-r--r--tests/ui/crashes/ice-1782.rs2
-rw-r--r--tests/ui/crashes/ice-1969.rs2
-rw-r--r--tests/ui/crashes/ice-2499.rs2
-rw-r--r--tests/ui/crashes/ice-2594.rs2
-rw-r--r--tests/ui/crashes/ice-2636.rs22
-rw-r--r--tests/ui/crashes/ice-2636.stderr17
-rw-r--r--tests/ui/crashes/ice-2727.rs2
-rw-r--r--tests/ui/crashes/ice-2760.rs2
-rw-r--r--tests/ui/crashes/ice-2774.rs2
-rw-r--r--tests/ui/crashes/ice-2862.rs2
-rw-r--r--tests/ui/crashes/ice-2865.rs2
-rw-r--r--tests/ui/crashes/ice-3151.rs2
-rw-r--r--tests/ui/crashes/ice-3462.rs2
-rw-r--r--tests/ui/crashes/ice-3741.rs1
-rw-r--r--tests/ui/crashes/ice-3747.rs2
-rw-r--r--tests/ui/crashes/ice-4727.rs2
-rw-r--r--tests/ui/crashes/ice-4760.rs1
-rw-r--r--tests/ui/crashes/ice-700.rs2
-rw-r--r--tests/ui/crashes/ice_exacte_size.rs2
-rw-r--r--tests/ui/crashes/if_same_then_else.rs2
-rw-r--r--tests/ui/crashes/issue-825.rs2
-rw-r--r--tests/ui/crashes/issues_loop_mut_cond.rs2
-rw-r--r--tests/ui/crashes/match_same_arms_const.rs2
-rw-r--r--tests/ui/crashes/mut_mut_macro.rs2
-rw-r--r--tests/ui/crashes/needless_borrow_fp.rs2
-rw-r--r--tests/ui/crashes/needless_lifetimes_impl_trait.rs2
-rw-r--r--tests/ui/crashes/procedural_macro.rs2
-rw-r--r--tests/ui/crashes/regressions.rs2
-rw-r--r--tests/ui/crashes/returns.rs2
-rw-r--r--tests/ui/crashes/single-match-else.rs2
-rw-r--r--tests/ui/crashes/trivial_bounds.rs2
-rw-r--r--tests/ui/crashes/used_underscore_binding_macro.rs2
-rw-r--r--tests/ui/create_dir.fixed17
-rw-r--r--tests/ui/create_dir.rs17
-rw-r--r--tests/ui/create_dir.stderr16
-rw-r--r--tests/ui/declare_interior_mutable_const.rs161
-rw-r--r--tests/ui/declare_interior_mutable_const.stderr84
-rw-r--r--tests/ui/drop_ref.rs1
-rw-r--r--tests/ui/drop_ref.stderr36
-rw-r--r--tests/ui/explicit_counter_loop.rs29
-rw-r--r--tests/ui/float_cmp.stderr22
-rw-r--r--tests/ui/float_cmp_const.stderr30
-rw-r--r--tests/ui/indexing_slicing_index.rs3
-rw-r--r--tests/ui/indexing_slicing_index.stderr20
-rw-r--r--tests/ui/indexing_slicing_slice.stderr26
-rw-r--r--tests/ui/into_iter_on_ref.stderr54
-rw-r--r--tests/ui/let_if_seq.rs1
-rw-r--r--tests/ui/let_if_seq.stderr8
-rw-r--r--tests/ui/manual_strip.rs66
-rw-r--r--tests/ui/manual_strip.stderr132
-rw-r--r--tests/ui/map_err.rs25
-rw-r--r--tests/ui/map_err.stderr11
-rw-r--r--tests/ui/match_type_on_diag_item.rs50
-rw-r--r--tests/ui/match_type_on_diag_item.stderr33
-rw-r--r--tests/ui/needless_arbitrary_self_type_unfixable.rs45
-rw-r--r--tests/ui/needless_arbitrary_self_type_unfixable.stderr10
-rw-r--r--tests/ui/option_if_let_else.fixed10
-rw-r--r--tests/ui/option_if_let_else.rs15
-rw-r--r--tests/ui/option_if_let_else.stderr36
-rw-r--r--tests/ui/option_map_unit_fn_fixable.stderr36
-rw-r--r--tests/ui/or_fun_call.fixed25
-rw-r--r--tests/ui/or_fun_call.rs25
-rw-r--r--tests/ui/or_fun_call.stderr20
-rw-r--r--tests/ui/panic_in_result_fn.rs70
-rw-r--r--tests/ui/panic_in_result_fn.stderr105
-rw-r--r--tests/ui/print_stdout_build_script.rs12
-rw-r--r--tests/ui/print_with_newline.rs1
-rw-r--r--tests/ui/print_with_newline.stderr23
-rw-r--r--tests/ui/rc_buffer.rs26
-rw-r--r--tests/ui/rc_buffer.stderr52
-rw-r--r--tests/ui/rc_buffer_arc.rs25
-rw-r--r--tests/ui/rc_buffer_arc.stderr52
-rw-r--r--tests/ui/rc_buffer_redefined_string.rs12
-rw-r--r--tests/ui/rc_buffer_redefined_string.stderr0
-rw-r--r--tests/ui/redundant_pattern_matching.fixed107
-rw-r--r--tests/ui/redundant_pattern_matching.rs102
-rw-r--r--tests/ui/redundant_pattern_matching.stderr162
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.fixed44
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.rs50
-rw-r--r--tests/ui/redundant_pattern_matching_const_result.stderr46
-rw-r--r--tests/ui/redundant_pattern_matching_option.fixed85
-rw-r--r--tests/ui/redundant_pattern_matching_option.rs100
-rw-r--r--tests/ui/redundant_pattern_matching_option.stderr134
-rw-r--r--tests/ui/result_map_unit_fn_fixable.stderr34
-rw-r--r--tests/ui/result_map_unit_fn_unfixable.stderr12
-rw-r--r--tests/ui/same_item_push.rs103
-rw-r--r--tests/ui/same_item_push.stderr42
-rw-r--r--tests/ui/temporary_assignment.rs5
-rw-r--r--tests/ui/temporary_assignment.stderr26
-rw-r--r--tests/ui/trailing_zeros.rs1
-rw-r--r--tests/ui/trailing_zeros.stderr4
-rw-r--r--tests/ui/unit_arg.rs13
-rw-r--r--tests/ui/unit_arg.stderr96
-rw-r--r--tests/ui/unit_arg_empty_blocks.stderr14
-rw-r--r--tests/ui/unnecessary_lazy_eval.fixed43
-rw-r--r--tests/ui/unnecessary_lazy_eval.rs25
-rw-r--r--tests/ui/unnecessary_lazy_eval.stderr112
-rw-r--r--tests/ui/unnecessary_sort_by.fixed42
-rw-r--r--tests/ui/unnecessary_sort_by.rs42
-rw-r--r--tests/ui/useless_conversion.stderr22
-rw-r--r--tests/ui/useless_conversion_try.stderr18
-rw-r--r--tests/ui/write_with_newline.rs1
-rw-r--r--tests/ui/write_with_newline.stderr23
-rw-r--r--triagebot.toml2
193 files changed, 4806 insertions, 1610 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99a8b1a6293..575cbd60792 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1547,6 +1547,7 @@ Released 2018-09-13
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
+[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
@@ -1558,6 +1559,7 @@ Released 2018-09-13
 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
+[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -1671,10 +1673,12 @@ Released 2018-09-13
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`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
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
+[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 [`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
@@ -1754,6 +1758,7 @@ Released 2018-09-13
 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
+[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
@@ -1773,6 +1778,7 @@ Released 2018-09-13
 [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
+[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
 [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
 [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 54777810abb..100c9edb367 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ something. We appreciate any sort of contributions, and don't want a wall of rul
 
 Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
 explains how you can contribute and how to get started.  If you have any questions about contributing or need help with
-anything, feel free to ask questions on issues or visit the `#clippy` on [Discord].
+anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip].
 
 All contributors are expected to follow the [Rust Code of Conduct].
 
@@ -23,7 +23,7 @@ All contributors are expected to follow the [Rust Code of Conduct].
   - [Bors and Homu](#bors-and-homu)
   - [Contributions](#contributions)
 
-[Discord]: https://discord.gg/rust-lang
+[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
 [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
 
 ## Getting started
@@ -242,7 +242,7 @@ to be run inside the `rust` directory):
     ```
 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
    accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
-   ~~annoy~~ ask them in the [Discord] channel.)
+   ~~annoy~~ ask them in the [Zulip] stream.)
    
 ### Syncing back changes in Clippy to [`rust-lang/rust`]
 
diff --git a/README.md b/README.md
index a2984d73641..62a8be0abf2 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
 
diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs
index f2bd651ab25..c67efc10f15 100644
--- a/clippy_dev/src/ra_setup.rs
+++ b/clippy_dev/src/ra_setup.rs
@@ -14,7 +14,7 @@ pub fn run(rustc_path: Option<&str>) {
     // we can unwrap here because the arg is required here
     let rustc_path = PathBuf::from(rustc_path.unwrap());
     assert!(rustc_path.is_dir(), "path is not a directory");
-    let rustc_source_basedir = rustc_path.join("src");
+    let rustc_source_basedir = rustc_path.join("compiler");
     assert!(
         rustc_source_basedir.is_dir(),
         "are you sure the path leads to a rustc repo?"
@@ -61,7 +61,7 @@ fn inject_deps_into_manifest(
     let new_deps = extern_crates.map(|dep| {
         // format the dependencies that are going to be put inside the Cargo.toml
         format!(
-            "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n",
+            "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
             dep = dep,
             source_path = rustc_source_dir.display()
         )
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index cc7d3a04f00..341d9e601ee 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -21,7 +21,7 @@ cargo_metadata = "0.11.1"
 if_chain = "1.0.0"
 itertools = "0.9"
 lazy_static = "1.0.2"
-pulldown-cmark = { version = "0.7.1", default-features = false }
+pulldown-cmark = { version = "0.8", default-features = false }
 quine-mc_cluskey = "0.2.2"
 regex-syntax = "0.6"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs
index 2d964ac2b9f..703d8a6f62b 100644
--- a/clippy_lints/src/atomic_ordering.rs
+++ b/clippy_lints/src/atomic_ordering.rs
@@ -8,7 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of invalid atomic
-    /// ordering in atomic loads/stores and memory fences.
+    /// ordering in atomic loads/stores/exchanges/updates and
+    /// memory fences.
     ///
     /// **Why is this bad?** Using an invalid atomic ordering
     /// will cause a panic at run-time.
@@ -17,22 +18,35 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust,no_run
-    /// # use std::sync::atomic::{self, AtomicBool, Ordering};
+    /// # use std::sync::atomic::{self, AtomicU8, Ordering};
     ///
-    /// let x = AtomicBool::new(true);
+    /// let x = AtomicU8::new(0);
     ///
+    /// // Bad: `Release` and `AcqRel` cannot be used for `load`.
     /// let _ = x.load(Ordering::Release);
     /// let _ = x.load(Ordering::AcqRel);
     ///
-    /// x.store(false, Ordering::Acquire);
-    /// x.store(false, Ordering::AcqRel);
+    /// // Bad: `Acquire` and `AcqRel` cannot be used for `store`.
+    /// x.store(1, Ordering::Acquire);
+    /// x.store(2, Ordering::AcqRel);
     ///
+    /// // Bad: `Relaxed` cannot be used as a fence's ordering.
     /// atomic::fence(Ordering::Relaxed);
     /// atomic::compiler_fence(Ordering::Relaxed);
+    ///
+    /// // Bad: `Release` and `AcqRel` are both always invalid
+    /// // for the failure ordering (the last arg).
+    /// let _ = x.compare_exchange(1, 2, Ordering::SeqCst, Ordering::Release);
+    /// let _ = x.compare_exchange_weak(2, 3, Ordering::AcqRel, Ordering::AcqRel);
+    ///
+    /// // Bad: The failure ordering is not allowed to be
+    /// // stronger than the success order, and `SeqCst` is
+    /// // stronger than `Relaxed`.
+    /// let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |val| Some(val + val));
     /// ```
     pub INVALID_ATOMIC_ORDERING,
     correctness,
-    "usage of invalid atomic ordering in atomic loads/stores and memory fences"
+    "usage of invalid atomic ordering in atomic operations and memory fences"
 }
 
 declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
@@ -127,9 +141,89 @@ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }
 }
 
+fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
+    if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
+        cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
+    } else {
+        None
+    }
+}
+
+fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if_chain! {
+        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+        let method = method_path.ident.name.as_str();
+        if type_is_atomic(cx, &args[0]);
+        if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
+        let (success_order_arg, failure_order_arg) = if method == "fetch_update" {
+            (&args[1], &args[2])
+        } else {
+            (&args[3], &args[4])
+        };
+        if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg);
+        then {
+            // Helper type holding on to some checking and error reporting data. Has
+            // - (success ordering name,
+            // - list of failure orderings forbidden by the success order,
+            // - suggestion message)
+            type OrdLintInfo = (&'static str, &'static [&'static str], &'static str);
+            let relaxed: OrdLintInfo = ("Relaxed", &["SeqCst", "Acquire"], "ordering mode `Relaxed`");
+            let acquire: OrdLintInfo = ("Acquire", &["SeqCst"], "ordering modes `Acquire` or `Relaxed`");
+            let seq_cst: OrdLintInfo = ("SeqCst", &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
+            let release = ("Release", relaxed.1, relaxed.2);
+            let acqrel = ("AcqRel", acquire.1, acquire.2);
+            let search = [relaxed, acquire, seq_cst, release, acqrel];
+
+            let success_lint_info = opt_ordering_defid(cx, success_order_arg)
+                .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
+                    search
+                        .iter()
+                        .find(|(ordering, ..)| {
+                            match_def_path(cx, success_ord_def_id,
+                                &["core", "sync", "atomic", "Ordering", ordering])
+                        })
+                        .copied()
+                });
+
+            if match_ordering_def_path(cx, fail_ordering_def_id, &["Release", "AcqRel"]) {
+                // If we don't know the success order is, use what we'd suggest
+                // if it were maximally permissive.
+                let suggested = success_lint_info.unwrap_or(seq_cst).2;
+                span_lint_and_help(
+                    cx,
+                    INVALID_ATOMIC_ORDERING,
+                    failure_order_arg.span,
+                    &format!(
+                        "{}'s failure ordering may not be `Release` or `AcqRel`",
+                        method,
+                    ),
+                    None,
+                    &format!("consider using {} instead", suggested),
+                );
+            } else if let Some((success_ord_name, bad_ords_given_success, suggested)) = success_lint_info {
+                if match_ordering_def_path(cx, fail_ordering_def_id, bad_ords_given_success) {
+                    span_lint_and_help(
+                        cx,
+                        INVALID_ATOMIC_ORDERING,
+                        failure_order_arg.span,
+                        &format!(
+                            "{}'s failure ordering may not be stronger than the success ordering of `{}`",
+                            method,
+                            success_ord_name,
+                        ),
+                        None,
+                        &format!("consider using {} instead", suggested),
+                    );
+                }
+            }
+        }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for AtomicOrdering {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         check_atomic_load_store(cx, expr);
         check_memory_fence(cx, expr);
+        check_atomic_compare_exchange(cx, expr);
     }
 }
diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs
index f18e7e5d997..367534499fd 100644
--- a/clippy_lints/src/await_holding_lock.rs
+++ b/clippy_lints/src/await_holding_lock.rs
@@ -10,7 +10,7 @@ declare_clippy_lint! {
     /// **What it does:** Checks for calls to await while holding a
     /// non-async-aware MutexGuard.
     ///
-    /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
+    /// **Why is this bad?** The Mutex types found in std::sync and parking_lot
     /// are not designed to operate in an async context across await points.
     ///
     /// There are two potential solutions. One is to use an asynx-aware Mutex
diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs
index 81a34021e8a..a4ee54076ee 100644
--- a/clippy_lints/src/bit_mask.rs
+++ b/clippy_lints/src/bit_mask.rs
@@ -90,7 +90,7 @@ declare_clippy_lint! {
     /// if x & 0b1111 == 0 { }
     /// ```
     pub VERBOSE_BIT_MASK,
-    style,
+    pedantic,
     "expressions where a bit mask is less readable than the corresponding method call"
 }
 
diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs
index 189c07427ae..d7d02ebf985 100644
--- a/clippy_lints/src/bytecount.rs
+++ b/clippy_lints/src/bytecount.rs
@@ -1,6 +1,5 @@
 use crate::utils::{
-    contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability,
-    span_lint_and_sugg, walk_ptrs_ty,
+    contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::UintTy;
@@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
                     if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
                     if op.node == BinOpKind::Eq;
                     if match_type(cx,
-                               walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])),
+                               cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(),
                                &paths::SLICE_ITER);
                     then {
                         let needle = match get_path_name(l) {
@@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
                                 _ => { return; }
                             }
                         };
-                        if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() {
+                        if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() {
                             return;
                         }
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs
index 3ee022e4e68..0000d39263e 100644
--- a/clippy_lints/src/consts.rs
+++ b/clippy_lints/src/consts.rs
@@ -21,7 +21,7 @@ pub enum Constant {
     /// A `String` (e.g., "abc").
     Str(String),
     /// A binary string (e.g., `b"abc"`).
-    Binary(Lrc<Vec<u8>>),
+    Binary(Lrc<[u8]>),
     /// A single `char` (e.g., `'a'`).
     Char(char),
     /// An integer's bit representation.
@@ -155,7 +155,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
+        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs
new file mode 100644
index 00000000000..4002fb655a5
--- /dev/null
+++ b/clippy_lints/src/create_dir.rs
@@ -0,0 +1,51 @@
+use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
+    ///
+    /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// std::fs::create_dir("foo");
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// std::fs::create_dir_all("foo");
+    /// ```
+    pub CREATE_DIR,
+    restriction,
+    "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`"
+}
+
+declare_lint_pass!(CreateDir => [CREATE_DIR]);
+
+impl LateLintPass<'_> for CreateDir {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if_chain! {
+            if let ExprKind::Call(ref func, ref args) = expr.kind;
+            if let ExprKind::Path(ref path) = func.kind;
+            if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    CREATE_DIR,
+                    expr.span,
+                    "calling `std::fs::create_dir` where there may be a better way",
+                    "consider calling `std::fs::create_dir_all` instead",
+                    format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+                    Applicability::MaybeIncorrect,
+                )
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs
new file mode 100644
index 00000000000..581c3242e37
--- /dev/null
+++ b/clippy_lints/src/disallowed_method.rs
@@ -0,0 +1,73 @@
+use crate::utils::span_lint;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Symbol;
+
+declare_clippy_lint! {
+    /// **What it does:** Lints for specific trait methods defined in clippy.toml
+    ///
+    /// **Why is this bad?** Some methods are undesirable in certain contexts,
+    /// and it would be beneficial to lint for them as needed.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// // example code where clippy issues a warning
+    /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // example code which does not raise clippy warning
+    /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed
+    /// ```
+    pub DISALLOWED_METHOD,
+    nursery,
+    "use of a disallowed method call"
+}
+
+#[derive(Clone, Debug)]
+pub struct DisallowedMethod {
+    disallowed: FxHashSet<Vec<Symbol>>,
+}
+
+impl DisallowedMethod {
+    pub fn new(disallowed: &FxHashSet<String>) -> Self {
+        Self {
+            disallowed: disallowed
+                .iter()
+                .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
+                .collect(),
+        }
+    }
+}
+
+impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind {
+            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
+
+            let method_call = cx.get_def_path(def_id);
+            if self.disallowed.contains(&method_call) {
+                let method = method_call
+                    .iter()
+                    .map(|s| s.to_ident_string())
+                    .collect::<Vec<_>>()
+                    .join("::");
+
+                span_lint(
+                    cx,
+                    DISALLOWED_METHOD,
+                    expr.span,
+                    &format!("use of a disallowed method `{}`", method),
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 50121a054c7..62bb70af06e 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -534,7 +534,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
             return false;
         }
 
-        let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
+        let s = s.strip_suffix('s').unwrap_or(s);
 
         s.chars().all(char::is_alphanumeric)
             && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs
index 8ece44878fe..c0529a34cc4 100644
--- a/clippy_lints/src/duration_subsec.rs
+++ b/clippy_lints/src/duration_subsec.rs
@@ -7,7 +7,7 @@ use rustc_span::source_map::Spanned;
 
 use crate::consts::{constant, Constant};
 use crate::utils::paths;
-use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec {
         if_chain! {
             if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
             if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
-            if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION);
+            if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION);
             if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
             then {
                 let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs
index d616502a82a..35a5d00f4aa 100644
--- a/clippy_lints/src/entry.rs
+++ b/clippy_lints/src/entry.rs
@@ -1,6 +1,6 @@
 use crate::utils::SpanlessEq;
 use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt};
-use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty};
+use crate::utils::{snippet_with_applicability, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
@@ -106,7 +106,7 @@ fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static
         if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
         then {
             let map = &params[0];
-            let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map));
+            let obj_ty = cx.typeck_results().expr_ty(map).peel_refs();
 
             return if match_type(cx, obj_ty, &paths::BTREEMAP) {
                 Some(("BTreeMap", map, key))
diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs
index a9294a87f15..67a46353856 100644
--- a/clippy_lints/src/enum_variants.rs
+++ b/clippy_lints/src/enum_variants.rs
@@ -285,7 +285,7 @@ impl EarlyLintPass for EnumVariantNames {
                             );
                         }
                     }
-                    if item.vis.node.is_pub() {
+                    if item.vis.kind.is_pub() {
                         let matching = partial_match(mod_camel, &item_camel);
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
@@ -316,7 +316,7 @@ impl EarlyLintPass for EnumVariantNames {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let lint = match item.vis.node {
+            let lint = match item.vis.kind {
                 VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
                 _ => ENUM_VARIANT_NAMES,
             };
diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs
index 000762334f6..a9e05fddbe7 100644
--- a/clippy_lints/src/fallible_impl_from.rs
+++ b/clippy_lints/src/fallible_impl_from.rs
@@ -1,7 +1,5 @@
 use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT};
-use crate::utils::{
-    is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty,
-};
+use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -96,7 +94,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+                let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
                 if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
                     || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
                 {
diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs
index 8bd85af8768..d6541010bca 100644
--- a/clippy_lints/src/format.rs
+++ b/clippy_lints/src/format.rs
@@ -1,7 +1,7 @@
 use crate::utils::paths;
 use crate::utils::{
     is_expn_of, is_type_diagnostic_item, last_path_segment, match_def_path, match_function_call, snippet,
-    span_lint_and_then, walk_ptrs_ty,
+    span_lint_and_then,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
@@ -90,7 +90,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
         if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
         if pats.len() == 1;
         then {
-            let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0]));
+            let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs();
             if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                 return None;
             }
diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs
index a28eda8be15..741195f3b10 100644
--- a/clippy_lints/src/indexing_slicing.rs
+++ b/clippy_lints/src/indexing_slicing.rs
@@ -88,7 +88,7 @@ declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Index(ref array, ref index) = &expr.kind {
-            let ty = cx.typeck_results().expr_ty(array);
+            let ty = cx.typeck_results().expr_ty(array).peel_refs();
             if let Some(range) = higher::range(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
                 if let ty::Array(_, s) = ty.kind() {
diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs
index f330fa8fab8..0877b44d901 100644
--- a/clippy_lints/src/inherent_to_string.rs
+++ b/clippy_lints/src/inherent_to_string.rs
@@ -5,7 +5,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 use crate::utils::{
     get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help,
-    trait_ref_of_method, walk_ptrs_ty,
+    trait_ref_of_method,
 };
 
 declare_clippy_lint! {
@@ -125,7 +125,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
     // Get the real type of 'self'
     let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id);
     let self_type = cx.tcx.fn_sig(fn_def_id).input(0);
-    let self_type = walk_ptrs_ty(self_type.skip_binder());
+    let self_type = self_type.skip_binder().peel_refs();
 
     // Emit either a warning or an error
     if implements_trait(cx, self_type, display_trait_id, &[]) {
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 42a98dc963d..c9c4891bb08 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -1,4 +1,4 @@
-use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg};
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -285,7 +285,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         })
     }
 
-    let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr));
+    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
     match ty.kind() {
         ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
             cx.tcx
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 0eb1d331366..529c2450541 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(concat_idents)]
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
+#![feature(in_band_lifetimes)]
 #![feature(or_patterns)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -170,10 +171,12 @@ mod collapsible_if;
 mod comparison_chain;
 mod copies;
 mod copy_iterator;
+mod create_dir;
 mod dbg_macro;
 mod default_trait_access;
 mod dereference;
 mod derive;
+mod disallowed_method;
 mod doc;
 mod double_comparison;
 mod double_parens;
@@ -229,7 +232,9 @@ mod macro_use;
 mod main_recursion;
 mod manual_async_fn;
 mod manual_non_exhaustive;
+mod manual_strip;
 mod map_clone;
+mod map_err_ignore;
 mod map_identity;
 mod map_unit_fn;
 mod match_on_vec_items;
@@ -268,6 +273,7 @@ mod open_options;
 mod option_env_unwrap;
 mod option_if_let_else;
 mod overflow_check_conditional;
+mod panic_in_result_fn;
 mod panic_unimplemented;
 mod partialeq_ne_impl;
 mod path_buf_push_overwrite;
@@ -513,6 +519,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &copies::MATCH_SAME_ARMS,
         &copies::SAME_FUNCTIONS_IN_IF_CONDITION,
         &copy_iterator::COPY_ITERATOR,
+        &create_dir::CREATE_DIR,
         &dbg_macro::DBG_MACRO,
         &default_trait_access::DEFAULT_TRAIT_ACCESS,
         &dereference::EXPLICIT_DEREF_METHODS,
@@ -520,6 +527,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
         &derive::EXPL_IMPL_CLONE_ON_COPY,
         &derive::UNSAFE_DERIVE_DESERIALIZE,
+        &disallowed_method::DISALLOWED_METHOD,
         &doc::DOC_MARKDOWN,
         &doc::MISSING_ERRORS_DOC,
         &doc::MISSING_SAFETY_DOC,
@@ -623,7 +631,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &main_recursion::MAIN_RECURSION,
         &manual_async_fn::MANUAL_ASYNC_FN,
         &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
+        &manual_strip::MANUAL_STRIP,
         &map_clone::MAP_CLONE,
+        &map_err_ignore::MAP_ERR_IGNORE,
         &map_identity::MAP_IDENTITY,
         &map_unit_fn::OPTION_MAP_UNIT_FN,
         &map_unit_fn::RESULT_MAP_UNIT_FN,
@@ -749,6 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &option_env_unwrap::OPTION_ENV_UNWRAP,
         &option_if_let_else::OPTION_IF_LET_ELSE,
         &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
+        &panic_in_result_fn::PANIC_IN_RESULT_FN,
         &panic_unimplemented::PANIC,
         &panic_unimplemented::PANIC_PARAMS,
         &panic_unimplemented::TODO,
@@ -833,6 +844,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &types::LET_UNIT_VALUE,
         &types::LINKEDLIST,
         &types::OPTION_OPTION,
+        &types::RC_BUFFER,
         &types::REDUNDANT_ALLOCATION,
         &types::TYPE_COMPLEXITY,
         &types::UNIT_ARG,
@@ -861,6 +873,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &utils::internal_lints::COMPILER_LINT_FUNCTIONS,
         &utils::internal_lints::DEFAULT_LINT,
         &utils::internal_lints::LINT_WITHOUT_LINT_PASS,
+        &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
         &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
         &utils::internal_lints::PRODUCE_ICE,
         &vec::USELESS_VEC,
@@ -916,6 +929,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
     store.register_late_pass(|| box methods::Methods);
     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 types::LetUnitValue);
     store.register_late_pass(|| box types::UnitCmp);
@@ -1044,6 +1058,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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_late_pass(|| box create_dir::CreateDir);
     store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
     store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes);
     store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
@@ -1088,6 +1103,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
     store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
     store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+    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,
@@ -1102,11 +1119,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box self_assignment::SelfAssignment);
     store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
     store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+    store.register_late_pass(|| box manual_strip::ManualStrip);
+    store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
         LintId::of(&arithmetic::INTEGER_ARITHMETIC),
         LintId::of(&as_conversions::AS_CONVERSIONS),
+        LintId::of(&create_dir::CREATE_DIR),
         LintId::of(&dbg_macro::DBG_MACRO),
         LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
         LintId::of(&exit::EXIT),
@@ -1131,6 +1154,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
         LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
         LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC),
+        LintId::of(&panic_in_result_fn::PANIC_IN_RESULT_FN),
         LintId::of(&panic_unimplemented::PANIC),
         LintId::of(&panic_unimplemented::TODO),
         LintId::of(&panic_unimplemented::UNIMPLEMENTED),
@@ -1148,6 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
         LintId::of(&attrs::INLINE_ALWAYS),
         LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK),
+        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
         LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
         LintId::of(&copies::MATCH_SAME_ARMS),
         LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
@@ -1176,6 +1201,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
         LintId::of(&loops::EXPLICIT_ITER_LOOP),
         LintId::of(&macro_use::MACRO_USE_IMPORTS),
+        LintId::of(&map_err_ignore::MAP_ERR_IGNORE),
         LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::MATCH_BOOL),
         LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
@@ -1226,6 +1252,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
         LintId::of(&utils::internal_lints::DEFAULT_LINT),
         LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+        LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
         LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
         LintId::of(&utils::internal_lints::PRODUCE_ICE),
     ]);
@@ -1245,7 +1272,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&attrs::USELESS_ATTRIBUTE),
         LintId::of(&bit_mask::BAD_BIT_MASK),
         LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
-        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
         LintId::of(&blacklisted_name::BLACKLISTED_NAME),
         LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
         LintId::of(&booleans::LOGIC_BUG),
@@ -1326,6 +1352,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&main_recursion::MAIN_RECURSION),
         LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
         LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
+        LintId::of(&manual_strip::MANUAL_STRIP),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
@@ -1470,6 +1497,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::CHAR_LIT_AS_U8),
         LintId::of(&types::FN_TO_NUMERIC_CAST),
         LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
+        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&types::TYPE_COMPLEXITY),
         LintId::of(&types::UNIT_ARG),
@@ -1503,7 +1531,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
         LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
-        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
         LintId::of(&blacklisted_name::BLACKLISTED_NAME),
         LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
         LintId::of(&collapsible_if::COLLAPSIBLE_IF),
@@ -1618,6 +1645,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
         LintId::of(&loops::MUT_RANGE_BOUND),
         LintId::of(&loops::WHILE_LET_LOOP),
+        LintId::of(&manual_strip::MANUAL_STRIP),
         LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
@@ -1771,6 +1799,7 @@ 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(&types::BOX_VEC),
+        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&vec::USELESS_VEC),
     ]);
@@ -1784,6 +1813,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
         LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
         LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(&disallowed_method::DISALLOWED_METHOD),
         LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
         LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
         LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs
index f13e369907b..7f998c63f49 100644
--- a/clippy_lints/src/loops.rs
+++ b/clippy_lints/src/loops.rs
@@ -1114,7 +1114,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
             if let Some(self_expr) = args.get(0);
             if let Some(pushed_item) = args.get(1);
             // Check that the method being called is push() on a Vec
-            if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC);
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type));
             if path.ident.name.as_str() == "push";
             then {
                 return Some((self_expr, pushed_item))
@@ -1131,6 +1131,27 @@ fn detect_same_item_push<'tcx>(
     body: &'tcx Expr<'_>,
     _: &'tcx Expr<'_>,
 ) {
+    fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
+        let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
+        let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
+
+        span_lint_and_help(
+            cx,
+            SAME_ITEM_PUSH,
+            vec.span,
+            "it looks like the same item is being pushed into this Vec",
+            None,
+            &format!(
+                "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
+                item_str, vec_str, item_str
+            ),
+        )
+    }
+
+    if !matches!(pat.kind, PatKind::Wild) {
+        return;
+    }
+
     // Determine whether it is safe to lint the body
     let mut same_item_push_visitor = SameItemPushVisitor {
         should_lint: true,
@@ -1149,43 +1170,41 @@ fn detect_same_item_push<'tcx>(
                 .map_or(false, |id| implements_trait(cx, ty, id, &[]))
             {
                 // Make sure that the push does not involve possibly mutating values
-                if let PatKind::Wild = pat.kind {
-                    let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
-                    let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
-                    if let ExprKind::Path(ref qpath) = pushed_item.kind {
-                        if_chain! {
-                            if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id);
-                            let node = cx.tcx.hir().get(hir_id);
-                            if let Node::Binding(pat) = node;
-                            if let PatKind::Binding(bind_ann, ..) = pat.kind;
-                            if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
-                            then {
-                                span_lint_and_help(
-                                    cx,
-                                    SAME_ITEM_PUSH,
-                                    vec.span,
-                                    "it looks like the same item is being pushed into this Vec",
-                                    None,
-                                    &format!(
-                                        "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
-                                        item_str, vec_str, item_str
-                                    ),
-                                )
-                            }
+                match pushed_item.kind {
+                    ExprKind::Path(ref qpath) => {
+                        match qpath_res(cx, qpath, pushed_item.hir_id) {
+                            // immutable bindings that are initialized with literal or constant
+                            Res::Local(hir_id) => {
+                                if_chain! {
+                                    let node = cx.tcx.hir().get(hir_id);
+                                    if let Node::Binding(pat) = node;
+                                    if let PatKind::Binding(bind_ann, ..) = pat.kind;
+                                    if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+                                    let parent_node = cx.tcx.hir().get_parent_node(hir_id);
+                                    if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
+                                    if let Some(init) = parent_let_expr.init;
+                                    then {
+                                        match init.kind {
+                                            // immutable bindings that are initialized with literal
+                                            ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                                            // immutable bindings that are initialized with constant
+                                            ExprKind::Path(ref path) => {
+                                                if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) {
+                                                    emit_lint(cx, vec, pushed_item);
+                                                }
+                                            }
+                                            _ => {},
+                                        }
+                                    }
+                                }
+                            },
+                            // constant
+                            Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
+                            _ => {},
                         }
-                    } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
-                        span_lint_and_help(
-                            cx,
-                            SAME_ITEM_PUSH,
-                            vec.span,
-                            "it looks like the same item is being pushed into this Vec",
-                            None,
-                            &format!(
-                                "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
-                                item_str, vec_str, item_str
-                            ),
-                        )
-                    }
+                    },
+                    ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                    _ => {},
                 }
             }
         }
@@ -2115,7 +2134,7 @@ enum VarState {
     DontWarn,
 }
 
-/// Scan a for loop for variables that are incremented exactly once.
+/// Scan a for loop for variables that are incremented exactly once and not used after that.
 struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,          // context reference
     states: FxHashMap<HirId, VarState>, // incremented variables
@@ -2135,6 +2154,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
         if let Some(def_id) = var_def_id(self.cx, expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 let state = self.states.entry(def_id).or_insert(VarState::Initial);
+                if *state == VarState::IncrOnce {
+                    *state = VarState::DontWarn;
+                    return;
+                }
 
                 match parent.kind {
                     ExprKind::AssignOp(op, ref lhs, ref rhs) => {
@@ -2582,11 +2605,9 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
                         span,
                         NEEDLESS_COLLECT_MSG,
                         |diag| {
-                            let (arg, pred) = if contains_arg.starts_with('&') {
-                                ("x", &contains_arg[1..])
-                            } else {
-                                ("&x", &*contains_arg)
-                            };
+                            let (arg, pred) = contains_arg
+                                    .strip_prefix('&')
+                                    .map_or(("&x", &*contains_arg), |s| ("x", s));
                             diag.span_suggestion(
                                 span,
                                 "replace with",
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index 4e49bdbdd21..9c623821fdd 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -122,7 +122,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
 
 fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) {
     fn is_private(field: &StructField) -> bool {
-        matches!(field.vis.node, VisibilityKind::Inherited)
+        matches!(field.vis.kind, VisibilityKind::Inherited)
     }
 
     fn is_non_exhaustive_marker(field: &StructField) -> bool {
@@ -141,7 +141,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data:
 
     let fields = data.fields();
     let private_fields = fields.iter().filter(|f| is_private(f)).count();
-    let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count();
+    let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count();
 
     if_chain! {
         if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1;
diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs
new file mode 100644
index 00000000000..4afb0ab3bad
--- /dev/null
+++ b/clippy_lints/src/manual_strip.rs
@@ -0,0 +1,245 @@
+use crate::consts::{constant, Constant};
+use crate::utils::usage::mutated_variables;
+use crate::utils::{
+    eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
+};
+
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::BinOpKind;
+use rustc_hir::{BorrowKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
+    /// the pattern's length.
+    ///
+    /// **Why is this bad?**
+    /// Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no
+    /// slicing which may panic and the compiler does not need to insert this panic code. It is
+    /// also sometimes more readable as it removes the need for duplicating or storing the pattern
+    /// used by `str::{starts,ends}_with` and in the slicing.
+    ///
+    /// **Known problems:**
+    /// None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let s = "hello, world!";
+    /// if s.starts_with("hello, ") {
+    ///     assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let s = "hello, world!";
+    /// if let Some(end) = s.strip_prefix("hello, ") {
+    ///     assert_eq!(end.to_uppercase(), "WORLD!");
+    /// }
+    /// ```
+    pub MANUAL_STRIP,
+    complexity,
+    "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
+}
+
+declare_lint_pass!(ManualStrip => [MANUAL_STRIP]);
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum StripKind {
+    Prefix,
+    Suffix,
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualStrip {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if let Some((cond, then, _)) = higher::if_block(&expr);
+            if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
+            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
+            if let ExprKind::Path(target_path) = &target_arg.kind;
+            then {
+                let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
+                    StripKind::Prefix
+                } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) {
+                    StripKind::Suffix
+                } else {
+                    return;
+                };
+                let target_res = qpath_res(cx, &target_path, target_arg.hir_id);
+                if target_res == Res::Err {
+                    return;
+                };
+
+                if_chain! {
+                    if let Res::Local(hir_id) = target_res;
+                    if let Some(used_mutably) = mutated_variables(then, cx);
+                    if used_mutably.contains(&hir_id);
+                    then {
+                        return;
+                    }
+                }
+
+                let strippings = find_stripping(cx, strip_kind, target_res, pattern, then);
+                if !strippings.is_empty() {
+
+                    let kind_word = match strip_kind {
+                        StripKind::Prefix => "prefix",
+                        StripKind::Suffix => "suffix",
+                    };
+
+                    let test_span = expr.span.until(then.span);
+                    span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| {
+                        diag.span_note(test_span, &format!("the {} was tested here", kind_word));
+                        multispan_sugg(
+                            diag,
+                            &format!("try using the `strip_{}` method", kind_word),
+                            vec![(test_span,
+                                  format!("if let Some(<stripped>) = {}.strip_{}({}) ",
+                                          snippet(cx, target_arg.span, ".."),
+                                          kind_word,
+                                          snippet(cx, pattern.span, "..")))]
+                            .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
+                        )
+                    });
+                }
+            }
+        }
+    }
+}
+
+// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
+fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+    if_chain! {
+        if let ExprKind::MethodCall(_, _, [arg], _) = expr.kind;
+        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if match_def_path(cx, method_def_id, &paths::STR_LEN);
+        then {
+            Some(arg)
+        } else {
+            None
+        }
+    }
+}
+
+// Returns the length of the `expr` if it's a constant string or char.
+fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+    let (value, _) = constant(cx, cx.typeck_results(), expr)?;
+    match value {
+        Constant::Str(value) => Some(value.len() as u128),
+        Constant::Char(value) => Some(value.len_utf8() as u128),
+        _ => None,
+    }
+}
+
+// Tests if `expr` equals the length of the pattern.
+fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
+    if let ExprKind::Lit(Spanned {
+        node: LitKind::Int(n, _),
+        ..
+    }) = expr.kind
+    {
+        constant_length(cx, pattern).map_or(false, |length| length == n)
+    } else {
+        len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg))
+    }
+}
+
+// Tests if `expr` is a `&str`.
+fn is_ref_str(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match cx.typeck_results().expr_ty_adjusted(&expr).kind() {
+        ty::Ref(_, ty, _) => ty.is_str(),
+        _ => false,
+    }
+}
+
+// Removes the outer `AddrOf` expression if needed.
+fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> {
+    if let ExprKind::AddrOf(BorrowKind::Ref, _, unref) = &expr.kind {
+        unref
+    } else {
+        expr
+    }
+}
+
+// Find expressions where `target` is stripped using the length of `pattern`.
+// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
+// method.
+fn find_stripping<'tcx>(
+    cx: &LateContext<'tcx>,
+    strip_kind: StripKind,
+    target: Res,
+    pattern: &'tcx Expr<'_>,
+    expr: &'tcx Expr<'_>,
+) -> Vec<Span> {
+    struct StrippingFinder<'a, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        strip_kind: StripKind,
+        target: Res,
+        pattern: &'tcx Expr<'tcx>,
+        results: Vec<Span>,
+    }
+
+    impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
+        type Map = Map<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
+
+        fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+            if_chain! {
+                if is_ref_str(self.cx, ex);
+                let unref = peel_ref(ex);
+                if let ExprKind::Index(indexed, index) = &unref.kind;
+                if let Some(range) = higher::range(index);
+                if let higher::Range { start, end, .. } = range;
+                if let ExprKind::Path(path) = &indexed.kind;
+                if qpath_res(self.cx, path, ex.hir_id) == self.target;
+                then {
+                    match (self.strip_kind, start, end) {
+                        (StripKind::Prefix, Some(start), None) => {
+                            if eq_pattern_length(self.cx, self.pattern, start) {
+                                self.results.push(ex.span);
+                                return;
+                            }
+                        },
+                        (StripKind::Suffix, None, Some(end)) => {
+                            if_chain! {
+                                if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind;
+                                if let Some(left_arg) = len_arg(self.cx, left);
+                                if let ExprKind::Path(left_path) = &left_arg.kind;
+                                if qpath_res(self.cx, left_path, left_arg.hir_id) == self.target;
+                                if eq_pattern_length(self.cx, self.pattern, right);
+                                then {
+                                    self.results.push(ex.span);
+                                    return;
+                                }
+                            }
+                        },
+                        _ => {}
+                    }
+                }
+            }
+
+            walk_expr(self, ex);
+        }
+    }
+
+    let mut finder = StrippingFinder {
+        cx,
+        strip_kind,
+        target,
+        pattern,
+        results: vec![],
+    };
+    walk_expr(&mut finder, expr);
+    finder.results
+}
diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs
new file mode 100644
index 00000000000..5298e16a04d
--- /dev/null
+++ b/clippy_lints/src/map_err_ignore.rs
@@ -0,0 +1,147 @@
+use crate::utils::span_lint_and_help;
+
+use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for instances of `map_err(|_| Some::Enum)`
+    ///
+    /// **Why is this bad?** This map_err throws away the original error rather than allowing the enum to contain and report the cause of the error
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Before:
+    /// ```rust
+    /// use std::fmt;
+    ///
+    /// #[derive(Debug)]
+    /// enum Error {
+    ///     Indivisible,
+    ///     Remainder(u8),
+    /// }
+    ///
+    /// impl fmt::Display for Error {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         match self {
+    ///             Error::Indivisible => write!(f, "could not divide input by three"),
+    ///             Error::Remainder(remainder) => write!(
+    ///                 f,
+    ///                 "input is not divisible by three, remainder = {}",
+    ///                 remainder
+    ///             ),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for Error {}
+    ///
+    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+    ///     input
+    ///         .parse::<i32>()
+    ///         .map_err(|_| Error::Indivisible)
+    ///         .map(|v| v % 3)
+    ///         .and_then(|remainder| {
+    ///             if remainder == 0 {
+    ///                 Ok(())
+    ///             } else {
+    ///                 Err(Error::Remainder(remainder as u8))
+    ///             }
+    ///         })
+    /// }
+    ///  ```
+    ///
+    ///  After:
+    ///  ```rust
+    /// use std::{fmt, num::ParseIntError};
+    ///
+    /// #[derive(Debug)]
+    /// enum Error {
+    ///     Indivisible(ParseIntError),
+    ///     Remainder(u8),
+    /// }
+    ///
+    /// impl fmt::Display for Error {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         match self {
+    ///             Error::Indivisible(_) => write!(f, "could not divide input by three"),
+    ///             Error::Remainder(remainder) => write!(
+    ///                 f,
+    ///                 "input is not divisible by three, remainder = {}",
+    ///                 remainder
+    ///             ),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for Error {
+    ///     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+    ///         match self {
+    ///             Error::Indivisible(source) => Some(source),
+    ///             _ => None,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+    ///     input
+    ///         .parse::<i32>()
+    ///         .map_err(Error::Indivisible)
+    ///         .map(|v| v % 3)
+    ///         .and_then(|remainder| {
+    ///             if remainder == 0 {
+    ///                 Ok(())
+    ///             } else {
+    ///                 Err(Error::Remainder(remainder as u8))
+    ///             }
+    ///         })
+    /// }
+    /// ```
+    pub MAP_ERR_IGNORE,
+    pedantic,
+    "`map_err` should not ignore the original error"
+}
+
+declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]);
+
+impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
+    // do not try to lint if this is from a macro or desugaring
+    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
+        if e.span.from_expansion() {
+            return;
+        }
+
+        // check if this is a method call (e.g. x.foo())
+        if let ExprKind::MethodCall(ref method, _t_span, ref args, _) = e.kind {
+            // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
+            // Enum::Variant[2]))
+            if method.ident.as_str() == "map_err" && args.len() == 2 {
+                // make sure the first argument is a closure, and grab the CaptureRef, body_id, and body_span fields
+                if let ExprKind::Closure(capture, _, body_id, body_span, _) = args[1].kind {
+                    // check if this is by Reference (meaning there's no move statement)
+                    if capture == CaptureBy::Ref {
+                        // Get the closure body to check the parameters and values
+                        let closure_body = cx.tcx.hir().body(body_id);
+                        // make sure there's only one parameter (`|_|`)
+                        if closure_body.params.len() == 1 {
+                            // make sure that parameter is the wild token (`_`)
+                            if let PatKind::Wild = closure_body.params[0].pat.kind {
+                                // span the area of the closure capture and warn that the
+                                // original error will be thrown away
+                                span_lint_and_help(
+                                    cx,
+                                    MAP_ERR_IGNORE,
+                                    body_span,
+                                    "`map_err(|_|...` ignores the original error",
+                                    None,
+                                    "Consider wrapping the error in an enum variant",
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs
index 1f9ae8c931a..076ef235b8b 100644
--- a/clippy_lints/src/map_unit_fn.rs
+++ b/clippy_lints/src/map_unit_fn.rs
@@ -9,7 +9,7 @@ use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `option.map(f)` where f is a function
-    /// or closure that returns the unit type.
+    /// or closure that returns the unit type `()`.
     ///
     /// **Why is this bad?** Readability, this can be written more clearly with
     /// an if let statement
@@ -51,7 +51,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `result.map(f)` where f is a function
-    /// or closure that returns the unit type.
+    /// or closure that returns the unit type `()`.
     ///
     /// **Why is this bad?** Readability, this can be written more clearly with
     /// an if let statement
@@ -197,7 +197,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
 #[must_use]
 fn suggestion_msg(function_type: &str, map_type: &str) -> String {
     format!(
-        "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type",
+        "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`",
         map_type, function_type
     )
 }
diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs
index 57966452253..331b6c6c34a 100644
--- a/clippy_lints/src/match_on_vec_items.rs
+++ b/clippy_lints/src/match_on_vec_items.rs
@@ -1,4 +1,3 @@
-use crate::utils::walk_ptrs_ty;
 use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -90,12 +89,12 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
 
 fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
-    let ty = walk_ptrs_ty(ty);
+    let ty = ty.peel_refs();
     is_type_diagnostic_item(cx, ty, sym!(vec_type))
 }
 
 fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
-    let ty = walk_ptrs_ty(ty);
+    let ty = ty.peel_refs();
     is_type_lang_item(cx, ty, LangItem::RangeFull)
 }
diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs
index 7ba7397c29c..b1a4e06d4c3 100644
--- a/clippy_lints/src/matches.rs
+++ b/clippy_lints/src/matches.rs
@@ -6,7 +6,7 @@ use crate::utils::{
     expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
     is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet,
     snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
-    span_lint_and_then, walk_ptrs_ty,
+    span_lint_and_then,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
@@ -502,7 +502,7 @@ impl_lint_pass!(Matches => [
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
             return;
         }
 
@@ -794,7 +794,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms
 }
 
 fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex));
+    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
     if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
@@ -1440,15 +1440,12 @@ where
 
 mod redundant_pattern_match {
     use super::REDUNDANT_PATTERN_MATCHING;
-    use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+    use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
     use if_chain::if_chain;
     use rustc_ast::ast::LitKind;
     use rustc_errors::Applicability;
-    use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
+    use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
     use rustc_lint::LateContext;
-    use rustc_middle::ty;
-    use rustc_mir::const_eval::is_const_fn;
-    use rustc_span::source_map::Symbol;
 
     pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
@@ -1468,37 +1465,24 @@ mod redundant_pattern_match {
         arms: &[Arm<'_>],
         keyword: &'static str,
     ) {
-        fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
-            if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
-                return Some("is_ok()");
-            }
-            if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
-                return Some("is_err()");
-            }
-            if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
-                return Some("is_some()");
-            }
-            if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
-                return Some("is_none()");
-            }
-            None
-        }
-
-        let hir_id = expr.hir_id;
         let good_method = match arms[0].pat.kind {
             PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
                 if let PatKind::Wild = patterns[0].kind {
-                    find_suggestion(cx, hir_id, path)
+                    if match_qpath(path, &paths::RESULT_OK) {
+                        "is_ok()"
+                    } else if match_qpath(path, &paths::RESULT_ERR) {
+                        "is_err()"
+                    } else if match_qpath(path, &paths::OPTION_SOME) {
+                        "is_some()"
+                    } else {
+                        return;
+                    }
                 } else {
-                    None
+                    return;
                 }
             },
-            PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
-            _ => None,
-        };
-        let good_method = match good_method {
-            Some(method) => method,
-            None => return,
+            PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
+            _ => return,
         };
 
         // check that `while_let_on_iterator` lint does not trigger
@@ -1547,7 +1531,6 @@ mod redundant_pattern_match {
         if arms.len() == 2 {
             let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
-            let hir_id = expr.hir_id;
             let found_good_method = match node_pair {
                 (
                     PatKind::TupleStruct(ref path_left, ref patterns_left, _),
@@ -1562,8 +1545,6 @@ mod redundant_pattern_match {
                             &paths::RESULT_ERR,
                             "is_ok()",
                             "is_err()",
-                            || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
-                            || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
                         )
                     } else {
                         None
@@ -1582,8 +1563,6 @@ mod redundant_pattern_match {
                             &paths::OPTION_NONE,
                             "is_some()",
                             "is_none()",
-                            || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
-                            || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
                         )
                     } else {
                         None
@@ -1616,7 +1595,6 @@ mod redundant_pattern_match {
         }
     }
 
-    #[allow(clippy::too_many_arguments)]
     fn find_good_method_for_match<'a>(
         arms: &[Arm<'_>],
         path_left: &QPath<'_>,
@@ -1625,8 +1603,6 @@ mod redundant_pattern_match {
         expected_right: &[&str],
         should_be_left: &'a str,
         should_be_right: &'a str,
-        can_suggest_left: impl Fn() -> bool,
-        can_suggest_right: impl Fn() -> bool,
     ) -> Option<&'a str> {
         let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
             (&(*arms[0].body).kind, &(*arms[1].body).kind)
@@ -1638,35 +1614,13 @@ mod redundant_pattern_match {
 
         match body_node_pair {
             (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-                (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
-                (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
+                (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
+                (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
                 _ => None,
             },
             _ => None,
         }
     }
-
-    fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
-        if !in_constant(cx, hir_id) {
-            return true;
-        }
-
-        // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
-        cx.tcx
-            .get_diagnostic_item(diag_item)
-            .and_then(|def_id| {
-                cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
-                    cx.tcx
-                        .associated_items(*imp)
-                        .in_definition_order()
-                        .find_map(|item| match item.kind {
-                            ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
-                            _ => None,
-                        })
-                })
-            })
-            .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
-    }
 }
 
 #[test]
diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs
index 498f12518f8..ae37942e55a 100644
--- a/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -12,6 +12,7 @@ use rustc_middle::hir::map::Map;
 use rustc_span::Span;
 
 pub(crate) struct OptionAndThenSome;
+
 impl BindInsteadOfMap for OptionAndThenSome {
     const TYPE_NAME: &'static str = "Option";
     const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;
@@ -24,6 +25,7 @@ impl BindInsteadOfMap for OptionAndThenSome {
 }
 
 pub(crate) struct ResultAndThenOk;
+
 impl BindInsteadOfMap for ResultAndThenOk {
     const TYPE_NAME: &'static str = "Result";
     const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
@@ -36,6 +38,7 @@ impl BindInsteadOfMap for ResultAndThenOk {
 }
 
 pub(crate) struct ResultOrElseErrInfo;
+
 impl BindInsteadOfMap for ResultOrElseErrInfo {
     const TYPE_NAME: &'static str = "Result";
     const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
@@ -120,9 +123,9 @@ pub(crate) trait BindInsteadOfMap {
         }
     }
 
-    fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) {
+    fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
         let mut suggs = Vec::new();
-        let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
+        let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
             if_chain! {
                 if !in_macro(ret_expr.span);
                 if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
@@ -153,12 +156,13 @@ pub(crate) trait BindInsteadOfMap {
                 )
             });
         }
+        can_sugg
     }
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
-    fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+    fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
         if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
-            return;
+            return false;
         }
 
         match args[1].kind {
@@ -166,8 +170,10 @@ pub(crate) trait BindInsteadOfMap {
                 let closure_body = cx.tcx.hir().body(body_id);
                 let closure_expr = remove_blocks(&closure_body.value);
 
-                if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
-                    Self::lint_closure(cx, expr, closure_expr);
+                if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
+                    true
+                } else {
+                    Self::lint_closure(cx, expr, closure_expr)
                 }
             },
             // `_.and_then(Some)` case, which is no-op.
@@ -181,8 +187,9 @@ pub(crate) trait BindInsteadOfMap {
                     snippet(cx, args[0].span, "..").into(),
                     Applicability::MachineApplicable,
                 );
+                true
             },
-            _ => {},
+            _ => false,
         }
     }
 }
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index ba69c8266b1..dadd0f8ebb7 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -25,14 +25,15 @@ use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, SymbolStr};
 
 use crate::consts::{constant, Constant};
+use crate::utils::eager_or_lazy::is_lazyness_candidate;
 use crate::utils::usage::mutated_variables;
 use crate::utils::{
     contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
-    is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
-    last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
-    method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
-    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
-    span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
+    is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
+    match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
+    single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
+    span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth,
+    SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -1454,18 +1455,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
             ["unwrap_or_else", "map"] => {
                 if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
-                    unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or");
+                    unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or");
                 }
             },
             ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
             ["and_then", ..] => {
-                unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and");
-                bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
-                bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
+                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
+                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
+                if !biom_option_linted && !biom_result_linted {
+                    unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and");
+                }
             },
             ["or_else", ..] => {
-                unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
-                bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
+                if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) {
+                    unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or");
+                }
             },
             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
             ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
@@ -1508,9 +1512,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
             ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
             ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
-            ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"),
-            ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"),
-            ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"),
+            ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
+            ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
+            ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
             _ => {},
         }
 
@@ -1714,37 +1718,6 @@ fn lint_or_fun_call<'tcx>(
     name: &str,
     args: &'tcx [hir::Expr<'_>],
 ) {
-    // Searches an expression for method calls or function calls that aren't ctors
-    struct FunCallFinder<'a, 'tcx> {
-        cx: &'a LateContext<'tcx>,
-        found: bool,
-    }
-
-    impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
-        type Map = Map<'tcx>;
-
-        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-            let call_found = match &expr.kind {
-                // ignore enum and struct constructors
-                hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
-                hir::ExprKind::MethodCall(..) => true,
-                _ => false,
-            };
-
-            if call_found {
-                self.found |= true;
-            }
-
-            if !self.found {
-                intravisit::walk_expr(self, expr);
-            }
-        }
-
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::None
-        }
-    }
-
     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
@@ -1801,14 +1774,14 @@ fn lint_or_fun_call<'tcx>(
     ) {
         if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
             if path.ident.as_str() == "len" {
-                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+                let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
 
                 match ty.kind() {
                     ty::Slice(_) | ty::Array(_, _) => return,
                     _ => (),
                 }
 
-                if match_type(cx, ty, &paths::VEC) {
+                if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
                     return;
                 }
             }
@@ -1825,8 +1798,7 @@ fn lint_or_fun_call<'tcx>(
         if_chain! {
             if know_types.iter().any(|k| k.2.contains(&name));
 
-            let mut finder = FunCallFinder { cx: &cx, found: false };
-            if { finder.visit_expr(&arg); finder.found };
+            if is_lazyness_candidate(cx, arg);
             if !contains_return(&arg);
 
             let self_ty = cx.typeck_results().expr_ty(self_expr);
@@ -1909,7 +1881,7 @@ fn lint_expect_fun_call(
                         && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
                         && {
                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
-                            let base_type = walk_ptrs_ty(arg_type);
+                            let base_type = arg_type.peel_refs();
                             *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
                         }
                     {
@@ -2170,7 +2142,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
 }
 
 fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
-    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
+    let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
 
     if let ty::Adt(_, subst) = obj_ty.kind() {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -2201,7 +2173,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
     let arg = &args[1];
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
-        let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
+        let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if *self_ty.kind() == ty::Str {
             ""
         } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
@@ -2229,7 +2201,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
 }
 
 fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+    let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
     if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
         lint_string_extend(cx, expr, args);
     }
@@ -2412,7 +2384,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
         }
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
         || matches!(
-            &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(),
+            &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
             ty::Array(_, _)
         )
     {
@@ -2615,7 +2587,7 @@ fn derefs_to_slice<'tcx>(
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
 fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0]));
+    let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((UNWRAP_USED, "an Option", "None"))
@@ -2643,7 +2615,7 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E
 
 /// lint use of `expect()` for `Option`s and `Result`s
 fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0]));
+    let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((EXPECT_USED, "an Option", "None"))
@@ -3162,7 +3134,7 @@ fn lint_chars_cmp(
         if segment.ident.name == sym!(Some);
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
+            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
 
             if *self_ty.kind() != ty::Str {
                 return false;
@@ -3374,7 +3346,7 @@ fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_
             INTO_ITER_ON_REF,
             method_span,
             &format!(
-                "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`",
+                "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
                 method_name, kind,
             ),
             "call directly",
diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 31517659c34..08b3eab9b7c 100644
--- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -1,78 +1,17 @@
-use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg};
-use if_chain::if_chain;
+use crate::utils::{eager_or_lazy, usage};
+use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 
 use super::UNNECESSARY_LAZY_EVALUATIONS;
 
-// Return true if the expression is an accessor of any of the arguments
-fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool {
-    params.iter().any(|arg| {
-        if_chain! {
-            if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind;
-            if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind;
-            if let [p, ..] = path.segments;
-            then {
-                ident.name == p.ident.name
-            } else {
-                false
-            }
-        }
-    })
-}
-
-fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool {
-    paths.iter().any(|candidate| match_qpath(path, candidate))
-}
-
-fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool {
-    match expr.kind {
-        // Closures returning literals can be unconditionally simplified
-        hir::ExprKind::Lit(_) => true,
-
-        hir::ExprKind::Index(ref object, ref index) => {
-            // arguments are not being indexed into
-            if expr_uses_argument(object, params) {
-                false
-            } else {
-                // arguments are not used as index
-                !expr_uses_argument(index, params)
-            }
-        },
-
-        // Reading fields can be simplified if the object is not an argument of the closure
-        hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params),
-
-        // Paths can be simplified if the root is not the argument, this also covers None
-        hir::ExprKind::Path(_) => !expr_uses_argument(expr, params),
-
-        // Calls to Some, Ok, Err can be considered literals if they don't derive an argument
-        hir::ExprKind::Call(ref func, ref args) => if_chain! {
-            if variant_calls; // Disable lint when rules conflict with bind_instead_of_map
-            if let hir::ExprKind::Path(ref path) = func.kind;
-            if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]);
-            then {
-                // Recursively check all arguments
-                args.iter().all(|arg| can_simplify(arg, params, variant_calls))
-            } else {
-                false
-            }
-        },
-
-        // For anything more complex than the above, a closure is probably the right solution,
-        // or the case is handled by an other lint
-        _ => false,
-    }
-}
-
 /// lint use of `<fn>_else(simple closure)` for `Option`s and `Result`s that can be
 /// replaced with `<fn>(return value of simple closure)`
 pub(super) fn lint<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
-    allow_variant_calls: bool,
     simplify_using: &str,
 ) {
     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
@@ -81,10 +20,13 @@ pub(super) fn lint<'tcx>(
     if is_option || is_result {
         if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
             let body = cx.tcx.hir().body(eid);
-            let ex = &body.value;
-            let params = &body.params;
+            let body_expr = &body.value;
+
+            if usage::BindingUsageFinder::are_params_used(cx, body) {
+                return;
+            }
 
-            if can_simplify(ex, params, allow_variant_calls) {
+            if eager_or_lazy::is_eagerness_candidate(cx, body_expr) {
                 let msg = if is_option {
                     "unnecessary closure used to substitute value for `Option::None`"
                 } else {
@@ -101,7 +43,7 @@ pub(super) fn lint<'tcx>(
                         "{0}.{1}({2})",
                         snippet(cx, args[0].span, ".."),
                         simplify_using,
-                        snippet(cx, ex.span, ".."),
+                        snippet(cx, body_expr.span, ".."),
                     ),
                     Applicability::MachineApplicable,
                 );
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index d4a50dd9013..909e79f661a 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -17,7 +17,7 @@ use crate::utils::sugg::Sugg;
 use crate::utils::{
     get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats,
     last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg,
-    span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq,
+    span_lint_and_then, span_lint_hir_and_then, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -99,11 +99,11 @@ declare_clippy_lint! {
     /// if y != x {} // where both are floats
     ///
     /// // Good
-    /// let error = f64::EPSILON; // Use an epsilon for comparison
+    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
     /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error = std::f64::EPSILON;
-    /// if (y - 1.23f64).abs() < error { }
-    /// if (y - x).abs() > error { }
+    /// // let error_margin = std::f64::EPSILON;
+    /// if (y - 1.23f64).abs() < error_margin { }
+    /// if (y - x).abs() > error_margin { }
     /// ```
     pub FLOAT_CMP,
     correctness,
@@ -242,10 +242,10 @@ declare_clippy_lint! {
     /// if x == ONE { } // where both are floats
     ///
     /// // Good
-    /// let error = f64::EPSILON; // Use an epsilon for comparison
+    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
     /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error = std::f64::EPSILON;
-    /// if (x - ONE).abs() < error { }
+    /// // let error_margin = std::f64::EPSILON;
+    /// if (x - ONE).abs() < error_margin { }
     /// ```
     pub FLOAT_CMP_CONST,
     restriction,
@@ -411,16 +411,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                         if !is_comparing_arrays {
                             diag.span_suggestion(
                                 expr.span,
-                                "consider comparing them within some error",
+                                "consider comparing them within some margin of error",
                                 format!(
-                                    "({}).abs() {} error",
+                                    "({}).abs() {} error_margin",
                                     lhs - rhs,
                                     if op == BinOpKind::Eq { '<' } else { '>' }
                                 ),
                                 Applicability::HasPlaceholders, // snippet
                             );
                         }
-                        diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error`");
+                        diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`");
                     });
                 } else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) {
                     span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
@@ -561,7 +561,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind();
+    let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind();
 
     if let ty::Array(arr_ty, _) = value {
         return matches!(arr_ty.kind(), ty::Float(_));
@@ -571,7 +571,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _))
+    matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
 }
 
 fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs
index 02789735c17..9cb1cfb915d 100644
--- a/clippy_lints/src/misc_early.rs
+++ b/clippy_lints/src/misc_early.rs
@@ -377,8 +377,8 @@ impl EarlyLintPass for MiscEarlyLints {
             if let PatKind::Ident(_, ident, None) = arg.pat.kind {
                 let arg_name = ident.to_string();
 
-                if arg_name.starts_with('_') {
-                    if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
+                if let Some(arg_name) = arg_name.strip_prefix('_') {
+                    if let Some(correspondence) = registered_names.get(arg_name) {
                         span_lint(
                             cx,
                             DUPLICATE_UNDERSCORE_ARGUMENT,
@@ -386,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints {
                             &format!(
                                 "`{}` already exists, having another argument having almost the same \
                                  name makes code comprehension and documentation more difficult",
-                                arg_name[1..].to_owned()
+                                arg_name
                             ),
                         );
                     }
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index 1ad184dfc46..3e786da28df 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -1,10 +1,10 @@
+use crate::utils::qualify_min_const_fn::is_min_const_fn;
 use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 use rustc_typeck::hir_ty_to_ty;
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index 7423107e8f9..8a2dbdc50ea 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -1,4 +1,4 @@
-use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
+use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
@@ -12,8 +12,10 @@ declare_clippy_lint! {
     /// `BtreeSet` rely on either the hash or the order of keys be unchanging,
     /// so having types with interior mutability is a bad idea.
     ///
-    /// **Known problems:** We don't currently account for `Rc` or `Arc`, so
-    /// this may yield false positives.
+    /// **Known problems:** It's correct to use a struct, that contains interior mutability
+    /// as a key, when its `Hash` implementation doesn't access any of the interior mutable types.
+    /// However, this lint is unable to recognize this, so it causes a false positive in theses cases.
+    /// The `bytes` crate is a great example of this.
     ///
     /// **Example:**
     /// ```rust
@@ -96,7 +98,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
 // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
 // generics (because the compiler cannot ensure immutability for unknown types).
 fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
-    let ty = walk_ptrs_ty(ty);
+    let ty = ty.peel_refs();
     if let Adt(def, substs) = ty.kind() {
         if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
             .iter()
diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs
index 38bdd0f7ed2..7687962bdd9 100644
--- a/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,4 @@
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{in_macro, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
@@ -69,11 +69,30 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
         if let [segment] = &path.segments[..];
         if segment.ident.name == kw::SelfUpper;
         then {
+            // In case we have a named lifetime, we check if the name comes from expansion.
+            // If it does, at this point we know the rest of the parameter was written by the user,
+            // so let them decide what the name of the lifetime should be.
+            // See #6089 for more details.
+            let mut applicability = Applicability::MachineApplicable;
             let self_param = match (binding_mode, mutbl) {
                 (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ mut self".to_string()
+                    } else {
+                        format!("&{} mut self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Not) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ self".to_string()
+                    } else {
+                        format!("&{} self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Value, Mutability::Mut) => "mut self".to_string(),
                 (Mode::Value, Mutability::Not) => "self".to_string(),
             };
@@ -85,7 +104,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                 "the type of the `self` parameter does not need to be arbitrary",
                 "consider to change this parameter to",
                 self_param,
-                Applicability::MachineApplicable,
+                applicability,
             )
         }
     }
@@ -93,7 +112,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
 
 impl EarlyLintPass for NeedlessArbitrarySelfType {
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
-        if !p.is_self() {
+        // Bail out if the parameter it's not a receiver or was not written by the user
+        if !p.is_self() || in_macro(p.span) {
             return;
         }
 
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index 73eabd4207e..bb44eeb6adc 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -6,14 +6,16 @@ use std::ptr;
 
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
+use rustc_infer::traits::specialization_graph;
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{Ty, TypeFlags};
+use rustc_middle::ty::{AssocKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use rustc_typeck::hir_ty_to_ty;
 
-use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then};
+use crate::utils::{in_constant, qpath_res, span_lint_and_then};
+use if_chain::if_chain;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for declaration of `const` items which is interior
@@ -83,11 +85,10 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-#[allow(dead_code)]
 #[derive(Copy, Clone)]
 enum Source {
     Item { item: Span },
-    Assoc { item: Span, ty: Span },
+    Assoc { item: Span },
     Expr { expr: Span },
 }
 
@@ -110,10 +111,15 @@ impl Source {
 }
 
 fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
-    if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
-        // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
-        // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
-        // as well.
+    // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+    // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+    // 'unfrozen'. However, this code causes a false negative in which
+    // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
+    // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+    // since it works when a pointer indirection involves (`Cell<*const T>`).
+    // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+    // but I'm not sure whether it's a decent way, if possible.
+    if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) {
         return;
     }
 
@@ -127,11 +133,7 @@ fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
                 let const_kw_span = span.from_inner(InnerSpan::new(0, 5));
                 diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
             },
-            Source::Assoc { ty: ty_span, .. } => {
-                if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
-                    diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
-                }
-            },
+            Source::Assoc { .. } => (),
             Source::Expr { .. } => {
                 diag.help("assign this const to a local or static variable, and use the variable here");
             },
@@ -152,14 +154,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
         if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-            verify_ty_bound(
-                cx,
-                ty,
-                Source::Assoc {
-                    ty: hir_ty.span,
-                    item: trait_item.span,
-                },
-            );
+            // Normalize assoc types because ones originated from generic params
+            // bounded other traits could have their bound.
+            let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+            verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span });
         }
     }
 
@@ -167,17 +165,50 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
         if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
             let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
             let item = cx.tcx.hir().expect_item(item_hir_id);
-            // Ensure the impl is an inherent impl.
-            if let ItemKind::Impl { of_trait: None, .. } = item.kind {
-                let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-                verify_ty_bound(
-                    cx,
-                    ty,
-                    Source::Assoc {
-                        ty: hir_ty.span,
-                        item: impl_item.span,
-                    },
-                );
+
+            match &item.kind {
+                ItemKind::Impl {
+                    of_trait: Some(of_trait_ref),
+                    ..
+                } => {
+                    if_chain! {
+                        // Lint a trait impl item only when the definition is a generic type,
+                        // assuming a assoc const is not meant to be a interior mutable type.
+                        if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
+                        if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id)
+                            .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id);
+                        if cx
+                            .tcx
+                            .layout_of(cx.tcx.param_env(of_trait_def_id).and(
+                                // Normalize assoc types because ones originated from generic params
+                                // bounded other traits could have their bound at the trait defs;
+                                // and, in that case, the definition is *not* generic.
+                                cx.tcx.normalize_erasing_regions(
+                                    cx.tcx.param_env(of_trait_def_id),
+                                    cx.tcx.type_of(of_assoc_item.def_id),
+                                ),
+                            ))
+                            .is_err();
+                        then {
+                            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+                            let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+                            verify_ty_bound(
+                                cx,
+                                normalized,
+                                Source::Assoc {
+                                    item: impl_item.span,
+                                },
+                            );
+                        }
+                    }
+                },
+                ItemKind::Impl { of_trait: None, .. } => {
+                    let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+                    // Normalize assoc types originated from generic params.
+                    let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+                    verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span });
+                },
+                _ => (),
             }
         }
     }
diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs
index e99d0317ba2..73a99a3a2f8 100644
--- a/clippy_lints/src/open_options.rs
+++ b/clippy_lints/src/open_options.rs
@@ -1,4 +1,4 @@
-use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty};
+use crate::utils::{match_type, paths, span_lint};
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -30,7 +30,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
 impl<'tcx> LateLintPass<'tcx> for OpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
-            let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
+            let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
             if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
                 let mut options = Vec::new();
                 get_open_options(cx, &arguments[0], &mut options);
@@ -58,7 +58,7 @@ enum OpenOption {
 
 fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
     if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
-        let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
+        let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index 9494efe736c..4a3eb9c983a 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -1,6 +1,7 @@
 use crate::utils;
+use crate::utils::eager_or_lazy;
 use crate::utils::sugg::Sugg;
-use crate::utils::{match_type, paths, span_lint_and_sugg};
+use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg};
 use if_chain::if_chain;
 
 use rustc_errors::Applicability;
@@ -13,22 +14,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 declare_clippy_lint! {
     /// **What it does:**
     /// Lints usage of  `if let Some(v) = ... { y } else { x }` which is more
-    /// idiomatically done with `Option::map_or` (if the else bit is a simple
-    /// expression) or `Option::map_or_else` (if the else bit is a longer
-    /// block).
+    /// idiomatically done with `Option::map_or` (if the else bit is a pure
+    /// expression) or `Option::map_or_else` (if the else bit is an impure
+    /// expresion).
     ///
     /// **Why is this bad?**
     /// Using the dedicated functions of the Option type is clearer and
     /// more concise than an if let expression.
     ///
     /// **Known problems:**
-    /// This lint uses whether the block is just an expression or if it has
-    /// more statements to decide whether to use `Option::map_or` or
-    /// `Option::map_or_else`. If you have a single expression which calls
-    /// an expensive function, then it would be more efficient to use
-    /// `Option::map_or_else`, but this lint would suggest `Option::map_or`.
-    ///
-    /// Also, this lint uses a deliberately conservative metric for checking
+    /// This lint uses a deliberately conservative metric for checking
     /// if the inside of either body contains breaks or continues which will
     /// cause it to not suggest a fix if either block contains a loop with
     /// continues or breaks contained within the loop.
@@ -73,7 +68,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
     if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
         path.ident.name.to_ident_string() == "ok"
-            && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT)
+            && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type))
     } else {
         false
     }
@@ -92,6 +87,7 @@ struct OptionIfLetElseOccurence {
 struct ReturnBreakContinueMacroVisitor {
     seen_return_break_continue: bool,
 }
+
 impl ReturnBreakContinueMacroVisitor {
     fn new() -> ReturnBreakContinueMacroVisitor {
         ReturnBreakContinueMacroVisitor {
@@ -99,6 +95,7 @@ impl ReturnBreakContinueMacroVisitor {
         }
     }
 }
+
 impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
     type Map = Map<'tcx>;
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -157,7 +154,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
 }
 
 /// If this is the else body of an if/else expression, then we need to wrap
-/// it in curcly braces. Otherwise, we don't.
+/// it in curly braces. Otherwise, we don't.
 fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
         if let Some(Expr {
@@ -199,7 +196,10 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
 /// If this expression is the option if let/else construct we're detecting, then
 /// this function returns an `OptionIfLetElseOccurence` struct with details if
 /// this construct is found, or None if this construct is not found.
-fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OptionIfLetElseOccurence> {
+fn detect_option_if_let_else<'tcx>(
+    cx: &'_ LateContext<'tcx>,
+    expr: &'_ Expr<'tcx>,
+) -> Option<OptionIfLetElseOccurence> {
     if_chain! {
         if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly
         if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
@@ -214,10 +214,7 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
             let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
             let some_body = extract_body_from_arm(&arms[0])?;
             let none_body = extract_body_from_arm(&arms[1])?;
-            let method_sugg = match &none_body.kind {
-                ExprKind::Block(..) => "map_or_else",
-                _ => "map_or",
-            };
+            let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
             let capture_name = id.name.to_ident_string();
             let wrap_braces = should_wrap_in_braces(cx, expr);
             let (as_ref, as_mut) = match &cond_expr.kind {
@@ -243,8 +240,8 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
     }
 }
 
-impl<'a> LateLintPass<'a> for OptionIfLetElse {
-    fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let Some(detection) = detect_option_if_let_else(cx, expr) {
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs
new file mode 100644
index 00000000000..4077aba6ef1
--- /dev/null
+++ b/clippy_lints/src/panic_in_result_fn.rs
@@ -0,0 +1,90 @@
+use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then};
+use rustc_hir as hir;
+use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result.
+    ///
+    /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence unimplemented, panic and unreachable should be avoided.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// fn result_with_panic() -> Result<bool, String>
+    /// {
+    ///     panic!("error");
+    /// }
+    /// ```
+    pub PANIC_IN_RESULT_FN,
+    restriction,
+    "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` "
+}
+
+declare_lint_pass!(PanicInResultFn  => [PANIC_IN_RESULT_FN]);
+
+impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_kind: FnKind<'tcx>,
+        _: &'tcx hir::FnDecl<'tcx>,
+        body: &'tcx hir::Body<'tcx>,
+        span: Span,
+        hir_id: hir::HirId,
+    ) {
+        if !matches!(fn_kind, FnKind::Closure(_))
+            && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type))
+        {
+            lint_impl_body(cx, span, body);
+        }
+    }
+}
+
+struct FindPanicUnimplementedUnreachable {
+    result: Vec<Span>,
+}
+
+impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
+        if ["unimplemented", "unreachable", "panic", "todo"]
+            .iter()
+            .any(|fun| is_expn_of(expr.span, fun).is_some())
+        {
+            self.result.push(expr.span);
+        }
+        // and check sub-expressions
+        intravisit::walk_expr(self, expr);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
+
+fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
+    let mut panics = FindPanicUnimplementedUnreachable { result: Vec::new() };
+    panics.visit_expr(&body.value);
+    if !panics.result.is_empty() {
+        span_lint_and_then(
+            cx,
+            PANIC_IN_RESULT_FN,
+            impl_span,
+            "used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`",
+            move |diag| {
+                diag.help(
+                    "`unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing",
+                );
+                diag.span_note(panics.result, "return Err() instead of panicking");
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs
index b8583402928..6eeb031d383 100644
--- a/clippy_lints/src/path_buf_push_overwrite.rs
+++ b/clippy_lints/src/path_buf_push_overwrite.rs
@@ -1,4 +1,4 @@
-use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{match_type, paths, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             if path.ident.name == sym!(push);
             if args.len() == 2;
-            if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::PATH_BUF);
+            if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::PATH_BUF);
             if let Some(get_index_arg) = args.get(1);
             if let ExprKind::Lit(ref lit) = get_index_arg.kind;
             if let LitKind::Str(ref path_lit, _) = lit.node;
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index 4773731e327..4d20a819804 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -14,7 +14,6 @@ use rustc_middle::mir::{
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
 };
 use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
-use rustc_mir::dataflow::BottomValue;
 use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
@@ -88,6 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
 
         let maybe_storage_live_result = MaybeStorageLive
             .into_engine(cx.tcx, mir, def_id.to_def_id())
+            .pass_name("redundant_clone")
             .iterate_to_fixpoint()
             .into_results_cursor(mir);
         let mut possible_borrower = {
@@ -240,10 +240,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                         );
                         let mut app = Applicability::MaybeIncorrect;
 
-                        let mut call_snip = &snip[dot + 1..];
+                        let call_snip = &snip[dot + 1..];
                         // Machine applicable when `call_snip` looks like `foobar()`
-                        if call_snip.ends_with("()") {
-                            call_snip = call_snip[..call_snip.len()-2].trim();
+                        if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
                             if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
                                 app = Applicability::MachineApplicable;
                             }
@@ -411,14 +410,15 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
 struct MaybeStorageLive;
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
+    type Domain = BitSet<mir::Local>;
     const NAME: &'static str = "maybe_storage_live";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
         for arg in body.args_iter() {
             state.insert(arg);
         }
@@ -426,6 +426,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
+    type Idx = mir::Local;
+
     fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
         match stmt.kind {
             mir::StatementKind::StorageLive(l) => trans.gen(l),
@@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
     }
 }
 
-impl BottomValue for MaybeStorageLive {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs
index c0890018d46..ae601353009 100644
--- a/clippy_lints/src/repeat_once.rs
+++ b/clippy_lints/src/repeat_once.rs
@@ -1,5 +1,5 @@
 use crate::consts::{constant_context, Constant};
-use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
             if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
             if !in_macro(receiver.span);
             then {
-                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver));
+                let ty = cx.typeck_results().expr_ty(&receiver).peel_refs();
                 if ty.is_str() {
                     span_lint_and_sugg(
                         cx,
diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs
index 087d50c90e6..225fe58906f 100644
--- a/clippy_lints/src/shadow.rs
+++ b/clippy_lints/src/shadow.rs
@@ -25,7 +25,6 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # let x = 1;
-    ///
     /// // Bad
     /// let x = &x;
     ///
@@ -75,7 +74,9 @@ declare_clippy_lint! {
     /// names to bindings or introducing more scopes to contain the bindings.
     ///
     /// **Known problems:** This lint, as the other shadowing related lints,
-    /// currently only catches very simple patterns.
+    /// currently only catches very simple patterns. Note that
+    /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level
+    /// for this lint.
     ///
     /// **Example:**
     /// ```rust
diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs
index 58bfd0bc553..35b38eca14d 100644
--- a/clippy_lints/src/single_component_path_imports.rs
+++ b/clippy_lints/src/single_component_path_imports.rs
@@ -41,7 +41,7 @@ impl EarlyLintPass for SingleComponentPathImports {
         if_chain! {
             if !in_macro(item.span);
             if cx.sess.opts.edition == Edition::Edition2018;
-            if !item.vis.node.is_pub();
+            if !item.vis.kind.is_pub();
             if let ItemKind::Use(use_tree) = &item.kind;
             if let segments = &use_tree.prefix.segments;
             if segments.len() == 1;
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 7a659bf779c..15b66684eab 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned;
 use if_chain::if_chain;
 
 use crate::utils::SpanlessEq;
-use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for string appends of the form `x = x + y` (without
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
 }
 
 fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), sym!(string_type))
+    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
 }
 
 fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs
index 47a73ca9a24..54b38d9f4ce 100644
--- a/clippy_lints/src/swap.rs
+++ b/clippy_lints/src/swap.rs
@@ -1,7 +1,6 @@
 use crate::utils::sugg::Sugg;
 use crate::utils::{
     differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then,
-    walk_ptrs_ty,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -194,7 +193,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
     if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
         if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
             if eq_expr_value(cx, lhs1, lhs2) {
-                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
+                let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
 
                 if matches!(ty.kind(), ty::Slice(_))
                     || matches!(ty.kind(), ty::Array(_, _))
diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs
index 1aeff1baa36..fb891866364 100644
--- a/clippy_lints/src/temporary_assignment.rs
+++ b/clippy_lints/src/temporary_assignment.rs
@@ -1,5 +1,4 @@
 use crate::utils::{is_adjusted, span_lint};
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -22,12 +21,8 @@ declare_clippy_lint! {
     "assignments to temporaries"
 }
 
-fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match &expr.kind {
-        ExprKind::Struct(..) | ExprKind::Tup(..) => true,
-        ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)),
-        _ => false,
-    }
+fn is_temporary(expr: &Expr<'_>) -> bool {
+    matches!(&expr.kind, ExprKind::Struct(..) | ExprKind::Tup(..))
 }
 
 declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]);
@@ -39,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment {
             while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind {
                 base = f;
             }
-            if is_temporary(cx, base) && !is_adjusted(cx, base) {
+            if is_temporary(base) && !is_adjusted(cx, base) {
                 span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
             }
         }
diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs
index c82deaa43b2..17d950169fd 100644
--- a/clippy_lints/src/types.rs
+++ b/clippy_lints/src/types.rs
@@ -11,8 +11,8 @@ use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
     BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
-    ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn,
-    TraitItem, TraitItemKind, TyKind, UnOp,
+    ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind,
+    TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
@@ -31,12 +31,13 @@ use crate::utils::paths;
 use crate::utils::{
     clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item,
     last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral,
-    qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability,
-    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
+    qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite,
+    span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
 };
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
     /// the heap. So if you `Box` it, you just add another level of indirection
@@ -65,6 +66,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
     /// the heap. So if you `Box` its contents, you just add another level of indirection.
@@ -167,6 +169,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
     /// general.
@@ -212,11 +215,42 @@ declare_clippy_lint! {
     "redundant allocation"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
+    ///
+    /// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+    /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
+    ///
+    /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+    /// works if there are no additional references yet, which usually defeats the purpose of
+    /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
+    /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
+    /// be used.
+    ///
+    /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+    /// cases where mutation only happens before there are any additional references.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// # use std::rc::Rc;
+    /// fn foo(interned: Rc<String>) { ... }
+    /// ```
+    ///
+    /// Better:
+    ///
+    /// ```rust,ignore
+    /// fn foo(interned: Rc<str>) { ... }
+    /// ```
+    pub RC_BUFFER,
+    perf,
+    "shared ownership of a buffer type"
+}
+
 pub struct Types {
     vec_box_size_threshold: u64,
 }
 
-impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]);
+impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]);
 
 impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
@@ -269,6 +303,19 @@ fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str])
     None
 }
 
+fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
+    if match_type_parameter(cx, qpath, &paths::STRING).is_some() {
+        return Some("str");
+    }
+    if match_type_parameter(cx, qpath, &paths::OS_STRING).is_some() {
+        return Some("std::ffi::OsStr");
+    }
+    if match_type_parameter(cx, qpath, &paths::PATH_BUF).is_some() {
+        return Some("std::path::Path");
+    }
+    None
+}
+
 fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
     let last = last_path_segment(qpath);
     if_chain! {
@@ -318,14 +365,15 @@ impl Types {
                 if let Some(def_id) = res.opt_def_id() {
                     if Some(def_id) == cx.tcx.lang_items().owned_box() {
                         if let Some(span) = match_borrows_parameter(cx, qpath) {
+                            let mut applicability = Applicability::MachineApplicable;
                             span_lint_and_sugg(
                                 cx,
                                 REDUNDANT_ALLOCATION,
                                 hir_ty.span,
                                 "usage of `Box<&T>`",
                                 "try",
-                                snippet(cx, span, "..").to_string(),
-                                Applicability::MachineApplicable,
+                                snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+                                applicability,
                             );
                             return; // don't recurse into the type
                         }
@@ -342,14 +390,15 @@ impl Types {
                         }
                     } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
                         if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
+                            let mut applicability = Applicability::MachineApplicable;
                             span_lint_and_sugg(
                                 cx,
                                 REDUNDANT_ALLOCATION,
                                 hir_ty.span,
                                 "usage of `Rc<Rc<T>>`",
                                 "try",
-                                snippet(cx, span, "..").to_string(),
-                                Applicability::MachineApplicable,
+                                snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+                                applicability,
                             );
                             return; // don't recurse into the type
                         }
@@ -365,25 +414,109 @@ impl Types {
                                 GenericArg::Type(ty) => ty.span,
                                 _ => return,
                             };
+                            let mut applicability = Applicability::MachineApplicable;
                             span_lint_and_sugg(
                                 cx,
                                 REDUNDANT_ALLOCATION,
                                 hir_ty.span,
                                 "usage of `Rc<Box<T>>`",
                                 "try",
-                                format!("Rc<{}>", snippet(cx, inner_span, "..")),
+                                format!(
+                                    "Rc<{}>",
+                                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                                ),
+                                applicability,
+                            );
+                            return; // don't recurse into the type
+                        }
+                        if let Some(alternate) = match_buffer_type(cx, qpath) {
+                            span_lint_and_sugg(
+                                cx,
+                                RC_BUFFER,
+                                hir_ty.span,
+                                "usage of `Rc<T>` when T is a buffer type",
+                                "try",
+                                format!("Rc<{}>", alternate),
+                                Applicability::MachineApplicable,
+                            );
+                            return; // don't recurse into the type
+                        }
+                        if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
+                            let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
+                                GenericArg::Type(ty) => match &ty.kind {
+                                    TyKind::Path(qpath) => qpath,
+                                    _ => return,
+                                },
+                                _ => return,
+                            };
+                            let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
+                                GenericArg::Type(ty) => ty.span,
+                                _ => return,
+                            };
+                            let mut applicability = Applicability::MachineApplicable;
+                            span_lint_and_sugg(
+                                cx,
+                                RC_BUFFER,
+                                hir_ty.span,
+                                "usage of `Rc<T>` when T is a buffer type",
+                                "try",
+                                format!(
+                                    "Rc<[{}]>",
+                                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                                ),
                                 Applicability::MachineApplicable,
                             );
                             return; // don't recurse into the type
                         }
                         if let Some(span) = match_borrows_parameter(cx, qpath) {
+                            let mut applicability = Applicability::MachineApplicable;
                             span_lint_and_sugg(
                                 cx,
                                 REDUNDANT_ALLOCATION,
                                 hir_ty.span,
                                 "usage of `Rc<&T>`",
                                 "try",
-                                snippet(cx, span, "..").to_string(),
+                                snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+                                applicability,
+                            );
+                            return; // don't recurse into the type
+                        }
+                    } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
+                        if let Some(alternate) = match_buffer_type(cx, qpath) {
+                            span_lint_and_sugg(
+                                cx,
+                                RC_BUFFER,
+                                hir_ty.span,
+                                "usage of `Arc<T>` when T is a buffer type",
+                                "try",
+                                format!("Arc<{}>", alternate),
+                                Applicability::MachineApplicable,
+                            );
+                            return; // don't recurse into the type
+                        }
+                        if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
+                            let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
+                                GenericArg::Type(ty) => match &ty.kind {
+                                    TyKind::Path(qpath) => qpath,
+                                    _ => return,
+                                },
+                                _ => return,
+                            };
+                            let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
+                                GenericArg::Type(ty) => ty.span,
+                                _ => return,
+                            };
+                            let mut applicability = Applicability::MachineApplicable;
+                            span_lint_and_sugg(
+                                cx,
+                                RC_BUFFER,
+                                hir_ty.span,
+                                "usage of `Arc<T>` when T is a buffer type",
+                                "try",
+                                format!(
+                                    "Arc<[{}]>",
+                                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                                ),
                                 Applicability::MachineApplicable,
                             );
                             return; // don't recurse into the type
@@ -543,7 +676,6 @@ impl Types {
                             // details.
                             return;
                         }
-                        let mut applicability = Applicability::MachineApplicable;
                         span_lint_and_sugg(
                             cx,
                             BORROWED_BOX,
@@ -553,8 +685,12 @@ impl Types {
                             format!(
                                 "&{}{}",
                                 ltopt,
-                                &snippet_with_applicability(cx, inner.span, "..", &mut applicability)
+                                &snippet(cx, inner.span, "..")
                             ),
+                            // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
+                            // because the trait impls of it will break otherwise;
+                            // and there may be other cases that result in invalid code.
+                            // For example, type coercion doesn't work nicely.
                             Applicability::Unspecified,
                         );
                         return; // don't recurse into the type
@@ -802,6 +938,45 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg {
     }
 }
 
+fn fmt_stmts_and_call(
+    cx: &LateContext<'_>,
+    call_expr: &Expr<'_>,
+    call_snippet: &str,
+    args_snippets: &[impl AsRef<str>],
+    non_empty_block_args_snippets: &[impl AsRef<str>],
+) -> String {
+    let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
+    let call_snippet_with_replacements = args_snippets
+        .iter()
+        .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1));
+
+    let mut stmts_and_call = non_empty_block_args_snippets
+        .iter()
+        .map(|it| it.as_ref().to_owned())
+        .collect::<Vec<_>>();
+    stmts_and_call.push(call_snippet_with_replacements);
+    stmts_and_call = stmts_and_call
+        .into_iter()
+        .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned())
+        .collect();
+
+    let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
+    // expr is not in a block statement or result expression position, wrap in a block
+    let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
+    if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
+        let block_indent = call_expr_indent + 4;
+        stmts_and_call_snippet =
+            reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
+        stmts_and_call_snippet = format!(
+            "{{\n{}{}\n{}}}",
+            " ".repeat(block_indent),
+            &stmts_and_call_snippet,
+            " ".repeat(call_expr_indent)
+        );
+    }
+    stmts_and_call_snippet
+}
+
 fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
     let (singular, plural) = if args_to_recover.len() > 1 {
@@ -844,43 +1019,52 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
                         Applicability::MaybeIncorrect,
                     );
                     or = "or ";
+                    applicability = Applicability::MaybeIncorrect;
                 });
-            let sugg = args_to_recover
+
+            let arg_snippets: Vec<String> = args_to_recover
+                .iter()
+                .filter_map(|arg| snippet_opt(cx, arg.span))
+                .collect();
+            let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover
                 .iter()
                 .filter(|arg| !is_empty_block(arg))
-                .enumerate()
-                .map(|(i, arg)| {
-                    let indent = if i == 0 {
-                        0
-                    } else {
-                        indent_of(cx, expr.span).unwrap_or(0)
-                    };
-                    format!(
-                        "{}{};",
-                        " ".repeat(indent),
-                        snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability)
-                    )
-                })
-                .collect::<Vec<String>>();
-            let mut and = "";
-            if !sugg.is_empty() {
-                let plural = if sugg.len() > 1 { "s" } else { "" };
-                db.span_suggestion(
-                    expr.span.with_hi(expr.span.lo()),
-                    &format!("{}move the expression{} in front of the call...", or, plural),
-                    format!("{}\n", sugg.join("\n")),
-                    applicability,
+                .filter_map(|arg| snippet_opt(cx, arg.span))
+                .collect();
+
+            if let Some(call_snippet) = snippet_opt(cx, expr.span) {
+                let sugg = fmt_stmts_and_call(
+                    cx,
+                    expr,
+                    &call_snippet,
+                    &arg_snippets,
+                    &arg_snippets_without_empty_blocks,
                 );
-                and = "...and "
+
+                if arg_snippets_without_empty_blocks.is_empty() {
+                    db.multipart_suggestion(
+                        &format!("use {}unit literal{} instead", singular, plural),
+                        args_to_recover
+                            .iter()
+                            .map(|arg| (arg.span, "()".to_string()))
+                            .collect::<Vec<_>>(),
+                        applicability,
+                    );
+                } else {
+                    let plural = arg_snippets_without_empty_blocks.len() > 1;
+                    let empty_or_s = if plural { "s" } else { "" };
+                    let it_or_them = if plural { "them" } else { "it" };
+                    db.span_suggestion(
+                        expr.span,
+                        &format!(
+                            "{}move the expression{} in front of the call and replace {} with the unit literal `()`",
+                            or, empty_or_s, it_or_them
+                        ),
+                        sugg,
+                        applicability,
+                    );
+                }
             }
-            db.multipart_suggestion(
-                &format!("{}use {}unit literal{} instead", and, singular, plural),
-                args_to_recover
-                    .iter()
-                    .map(|arg| (arg.span, "()".to_string()))
-                    .collect::<Vec<_>>(),
-                applicability,
-            );
         },
     );
 }
@@ -2055,6 +2239,7 @@ impl PartialOrd for FullInt {
         })
     }
 }
+
 impl Ord for FullInt {
     #[must_use]
     fn cmp(&self, other: &Self) -> Ordering {
diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs
index 8b00d29acb5..9b6a9075a29 100644
--- a/clippy_lints/src/unnecessary_sort_by.rs
+++ b/clippy_lints/src/unnecessary_sort_by.rs
@@ -1,5 +1,4 @@
 use crate::utils;
-use crate::utils::paths;
 use crate::utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -171,12 +170,22 @@ fn mirrored_exprs(
 }
 
 fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
+    // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
+    // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
+    // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
+    // than one level of references would add some extra complexity as we would have to compensate
+    // in the closure body.
+
     if_chain! {
         if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC);
+        let vec_ty = cx.typeck_results().expr_ty(vec);
+        if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
+        let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
+        if !matches!(&ty.kind(), ty::Ref(..));
+        if utils::is_copy(cx, ty);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs
index 1c7e62ecd3d..0f8797243ec 100644
--- a/clippy_lints/src/unwrap_in_result.rs
+++ b/clippy_lints/src/unwrap_in_result.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty};
+use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -81,7 +81,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
-            let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
             if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
                 || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
             {
@@ -91,7 +91,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
+            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
             if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
                 || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
             {
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 615440e15f3..4e4a206a583 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            "useless conversion to the same type",
+                            &format!("useless conversion to the same type: `{}`", b),
                             "consider removing `.into()`",
                             sugg,
                             Applicability::MachineApplicable, // snippet
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             cx,
                             USELESS_CONVERSION,
                             e.span,
-                            "useless conversion to the same type",
+                            &format!("useless conversion to the same type: `{}`", b),
                             "consider removing `.into_iter()`",
                             sugg,
                             Applicability::MachineApplicable, // snippet
@@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                                 cx,
                                 USELESS_CONVERSION,
                                 e.span,
-                                "useless conversion to the same type",
+                                &format!("useless conversion to the same type: `{}`", b),
                                 None,
                                 "consider removing `.try_into()`",
                             );
@@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                                     cx,
                                     USELESS_CONVERSION,
                                     e.span,
-                                    "useless conversion to the same type",
+                                    &format!("useless conversion to the same type: `{}`", b),
                                     None,
                                     &hint,
                                 );
@@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                                     cx,
                                     USELESS_CONVERSION,
                                     e.span,
-                                    "useless conversion to the same type",
+                                    &format!("useless conversion to the same type: `{}`", b),
                                     &sugg_msg,
                                     sugg.to_string(),
                                     Applicability::MachineApplicable, // snippet
diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs
index fa8dd210eba..0e9feef3746 100644
--- a/clippy_lints/src/utils/ast_utils.rs
+++ b/clippy_lints/src/utils/ast_utils.rs
@@ -394,7 +394,7 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
 
 pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
     use VisibilityKind::*;
-    match (&l.node, &r.node) {
+    match (&l.kind, &r.kind) {
         (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true,
         (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r),
         _ => false,
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 9c5a12ea9c8..03f8c5a2c07 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -164,6 +164,8 @@ define_Conf! {
     (max_fn_params_bools, "max_fn_params_bools": u64, 3),
     /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
     (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
+    /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
+    (disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
 }
 
 impl Default for Conf {
diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs
index e4e65b5f4d4..0a58231558e 100644
--- a/clippy_lints/src/utils/diagnostics.rs
+++ b/clippy_lints/src/utils/diagnostics.rs
@@ -51,6 +51,8 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 ///
 /// The `help` message can be optionally attached to a `Span`.
 ///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
 /// # Example
 ///
 /// ```ignore
@@ -87,6 +89,8 @@ pub fn span_lint_and_help<'a, T: LintContext>(
 /// The `note` message is presented separately from the main lint message
 /// and is attached to a specific span:
 ///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
 /// # Example
 ///
 /// ```ignore
@@ -126,6 +130,7 @@ pub fn span_lint_and_note<'a, T: LintContext>(
 /// Like `span_lint` but allows to add notes, help and suggestions using a closure.
 ///
 /// If you need to customize your lint output a lot, use this function.
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
 where
     F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
@@ -168,6 +173,10 @@ pub fn span_lint_hir_and_then(
 /// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
 /// 2)"`.
 ///
+/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
+/// # Example
+///
 /// ```ignore
 /// error: This `.fold` can be more succinctly expressed as `.any`
 /// --> $DIR/methods.rs:390:13
diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs
new file mode 100644
index 00000000000..6938d9971d9
--- /dev/null
+++ b/clippy_lints/src/utils/eager_or_lazy.rs
@@ -0,0 +1,128 @@
+//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa.
+//!
+//! Things to consider:
+//!  - has the expression side-effects?
+//!  - is the expression computationally expensive?
+//!
+//! See lints:
+//!  - unnecessary-lazy-evaluations
+//!  - or-fun-call
+//!  - option-if-let-else
+
+use crate::utils::is_ctor_or_promotable_const_function;
+use rustc_hir::def::{DefKind, Res};
+
+use rustc_hir::intravisit;
+use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+
+use rustc_hir::{Block, Expr, ExprKind, Path, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::hir::map::Map;
+
+/// Is the expr pure (is it free from side-effects)?
+/// This function is named so to stress that it isn't exhaustive and returns FNs.
+fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
+        ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
+        ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
+        ExprKind::Struct(_, fields, expr) => {
+            fields.iter().all(|f| identify_some_pure_patterns(f.expr))
+                && expr.map_or(true, |e| identify_some_pure_patterns(e))
+        },
+        ExprKind::Call(
+            &Expr {
+                kind:
+                    ExprKind::Path(QPath::Resolved(
+                        _,
+                        Path {
+                            res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..),
+                            ..
+                        },
+                    )),
+                ..
+            },
+            args,
+        ) => args.iter().all(|expr| identify_some_pure_patterns(expr)),
+        ExprKind::Block(
+            &Block {
+                stmts,
+                expr: Some(expr),
+                ..
+            },
+            _,
+        ) => stmts.is_empty() && identify_some_pure_patterns(expr),
+        ExprKind::Box(..)
+        | ExprKind::Array(..)
+        | ExprKind::Call(..)
+        | ExprKind::MethodCall(..)
+        | ExprKind::Binary(..)
+        | ExprKind::Unary(..)
+        | ExprKind::Cast(..)
+        | ExprKind::Type(..)
+        | ExprKind::DropTemps(..)
+        | ExprKind::Loop(..)
+        | ExprKind::Match(..)
+        | ExprKind::Closure(..)
+        | ExprKind::Block(..)
+        | ExprKind::Assign(..)
+        | ExprKind::AssignOp(..)
+        | ExprKind::Index(..)
+        | ExprKind::Break(..)
+        | ExprKind::Continue(..)
+        | ExprKind::Ret(..)
+        | ExprKind::InlineAsm(..)
+        | ExprKind::LlvmInlineAsm(..)
+        | ExprKind::Repeat(..)
+        | ExprKind::Yield(..)
+        | ExprKind::Err => false,
+    }
+}
+
+/// Identify some potentially computationally expensive patterns.
+/// This function is named so to stress that its implementation is non-exhaustive.
+/// It returns FNs and FPs.
+fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    // Searches an expression for method calls or function calls that aren't ctors
+    struct FunCallFinder<'a, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        found: bool,
+    }
+
+    impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
+        type Map = Map<'tcx>;
+
+        fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+            let call_found = match &expr.kind {
+                // ignore enum and struct constructors
+                ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
+                ExprKind::MethodCall(..) => true,
+                _ => false,
+            };
+
+            if call_found {
+                self.found |= true;
+            }
+
+            if !self.found {
+                intravisit::walk_expr(self, expr);
+            }
+        }
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
+    }
+
+    let mut finder = FunCallFinder { cx, found: false };
+    finder.visit_expr(expr);
+    finder.found
+}
+
+pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr)
+}
+
+pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    identify_some_potentially_expensive_patterns(cx, expr)
+}
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 8fa5d22210a..bfe426a25eb 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -1,6 +1,6 @@
 use crate::utils::{
-    is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint,
-    span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq,
+    is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
+    snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
@@ -11,7 +11,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind};
+use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
@@ -206,6 +206,29 @@ declare_clippy_lint! {
     "found collapsible `span_lint_and_then` calls"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `utils::match_type()` on a type diagnostic item
+    /// and suggests to use `utils::is_type_diagnostic_item()` instead.
+    ///
+    /// **Why is this bad?** `utils::is_type_diagnostic_item()` does not require hardcoded paths.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust,ignore
+    /// utils::match_type(cx, ty, &paths::VEC)
+    /// ```
+    ///
+    /// Good:
+    /// ```rust,ignore
+    /// utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))
+    /// ```
+    pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+    internal,
+    "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
+}
+
 declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 
 impl EarlyLintPass for ClippyLintsInternal {
@@ -404,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(&*fn_name.as_str());
-            let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+            let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
             if match_type(cx, ty, &paths::EARLY_CONTEXT)
                 || match_type(cx, ty, &paths::LATE_CONTEXT);
             then {
@@ -437,7 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
             let args = arg_lists[1];
             if args.len() == 1;
             let self_arg = &args[0];
-            let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg));
+            let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
                 span_lint_and_sugg(
@@ -652,3 +675,89 @@ fn suggest_note(
         Applicability::MachineApplicable,
     );
 }
+
+declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
+
+impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if !run_lints(cx, &[MATCH_TYPE_ON_DIAGNOSTIC_ITEM], expr.hir_id) {
+            return;
+        }
+
+        if_chain! {
+            // Check if this is a call to utils::match_type()
+            if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
+            if let ExprKind::Path(fn_qpath) = &fn_path.kind;
+            if match_qpath(&fn_qpath, &["utils", "match_type"]);
+            // Extract the path to the matched type
+            if let Some(segments) = path_to_matched_type(cx, ty_path);
+            let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
+            if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id());
+            // Check if the matched type is a diagnostic item
+            let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
+            if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
+            then {
+                let cx_snippet = snippet(cx, context.span, "_");
+                let ty_snippet = snippet(cx, ty.span, "_");
+
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+                    expr.span,
+                    "usage of `utils::match_type()` on a type diagnostic item",
+                    "try",
+                    format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
+
+fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
+    use rustc_hir::ItemKind;
+
+    match &expr.kind {
+        ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
+        ExprKind::Path(qpath) => match qpath_res(cx, qpath, expr.hir_id) {
+            Res::Local(hir_id) => {
+                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+                if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
+                    if let Some(init) = local.init {
+                        return path_to_matched_type(cx, init);
+                    }
+                }
+            },
+            Res::Def(DefKind::Const | DefKind::Static, def_id) => {
+                if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
+                    if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
+                        let body = cx.tcx.hir().body(body_id);
+                        return path_to_matched_type(cx, &body.value);
+                    }
+                }
+            },
+            _ => {},
+        },
+        ExprKind::Array(exprs) => {
+            let segments: Vec<SymbolStr> = exprs
+                .iter()
+                .filter_map(|expr| {
+                    if let ExprKind::Lit(lit) = &expr.kind {
+                        if let LitKind::Str(sym, _) = lit.node {
+                            return Some(sym.as_str());
+                        }
+                    }
+
+                    None
+                })
+                .collect();
+
+            if segments.len() == exprs.len() {
+                return Some(segments);
+            }
+        },
+        _ => {},
+    }
+
+    None
+}
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index bea0a4d2459..dfe2aadffc0 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -10,6 +10,7 @@ pub mod comparisons;
 pub mod conf;
 pub mod constants;
 mod diagnostics;
+pub mod eager_or_lazy;
 pub mod higher;
 mod hir_utils;
 pub mod inspector;
@@ -17,8 +18,10 @@ pub mod internal_lints;
 pub mod numeric_literal;
 pub mod paths;
 pub mod ptr;
+pub mod qualify_min_const_fn;
 pub mod sugg;
 pub mod usage;
+
 pub use self::attrs::*;
 pub use self::diagnostics::*;
 pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
@@ -44,7 +47,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
-use rustc_mir::const_eval;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
@@ -108,6 +110,7 @@ pub fn in_macro(span: Span) -> bool {
         false
     }
 }
+
 // If the snippet is empty, it's an attribute that was inserted during macro
 // expansion and we want to ignore those, because they could come from external
 // sources that the user has no control over.
@@ -128,6 +131,9 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
 }
 
 /// Checks if type is struct, enum or union type with the given def path.
+///
+/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
+/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
     match ty.kind() {
         ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
@@ -136,6 +142,8 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 }
 
 /// Checks if the type is equal to a diagnostic item
+///
+/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
     match ty.kind() {
         ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
@@ -571,7 +579,7 @@ pub fn snippet_block<'a, T: LintContext>(
 ) -> Cow<'a, str> {
     let snip = snippet(cx, span, default);
     let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
-    trim_multiline(snip, true, indent)
+    reindent_multiline(snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
@@ -585,7 +593,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
 ) -> Cow<'a, str> {
     let snip = snippet_with_applicability(cx, span, default, applicability);
     let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
-    trim_multiline(snip, true, indent)
+    reindent_multiline(snip, true, indent)
 }
 
 /// Returns a new Span that extends the original Span to the first non-whitespace char of the first
@@ -661,16 +669,16 @@ pub fn expr_block<'a, T: LintContext>(
     }
 }
 
-/// Trim indentation from a multiline string with possibility of ignoring the
-/// first line.
-fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
-    let s_space = trim_multiline_inner(s, ignore_first, indent, ' ');
-    let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t');
-    trim_multiline_inner(s_tab, ignore_first, indent, ' ')
+/// Reindent a multiline string with possibility of ignoring the first line.
+#[allow(clippy::needless_pass_by_value)]
+pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
+    let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' ');
+    let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t');
+    reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into()
 }
 
-fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>, ch: char) -> Cow<'_, str> {
-    let mut x = s
+fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String {
+    let x = s
         .lines()
         .skip(ignore_first as usize)
         .filter_map(|l| {
@@ -683,26 +691,20 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usiz
         })
         .min()
         .unwrap_or(0);
-    if let Some(indent) = indent {
-        x = x.saturating_sub(indent);
-    }
-    if x > 0 {
-        Cow::Owned(
-            s.lines()
-                .enumerate()
-                .map(|(i, l)| {
-                    if (ignore_first && i == 0) || l.is_empty() {
-                        l
-                    } else {
-                        l.split_at(x).1
-                    }
-                })
-                .collect::<Vec<_>>()
-                .join("\n"),
-        )
-    } else {
-        s
-    }
+    let indent = indent.unwrap_or(0);
+    s.lines()
+        .enumerate()
+        .map(|(i, l)| {
+            if (ignore_first && i == 0) || l.is_empty() {
+                l.to_owned()
+            } else if x > indent {
+                l.split_at(x - indent).1.to_owned()
+            } else {
+                " ".repeat(indent - x) + l
+            }
+        })
+        .collect::<Vec<String>>()
+        .join("\n")
 }
 
 /// Gets the parent expression, if any –- this is useful to constrain a lint.
@@ -752,14 +754,6 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
     }
 }
 
-/// Returns the base type for references and raw pointers.
-pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
-    match ty.kind() {
-        ty::Ref(_, ty, _) => walk_ptrs_ty(ty),
-        _ => ty,
-    }
-}
-
 /// Returns the base type for references and raw pointers, and count reference
 /// depth.
 pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
@@ -889,19 +883,11 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 
 /// 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 {
-    fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
-        cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
-    }
-
     if let ExprKind::Call(ref fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
-                // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
-                def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
-                    const_eval::is_const_fn(cx.tcx, def_id)
-                },
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
                 _ => false,
             };
@@ -1474,26 +1460,26 @@ macro_rules! unwrap_cargo_metadata {
 
 #[cfg(test)]
 mod test {
-    use super::{trim_multiline, without_block_comments};
+    use super::{reindent_multiline, without_block_comments};
 
     #[test]
-    fn test_trim_multiline_single_line() {
-        assert_eq!("", trim_multiline("".into(), false, None));
-        assert_eq!("...", trim_multiline("...".into(), false, None));
-        assert_eq!("...", trim_multiline("    ...".into(), false, None));
-        assert_eq!("...", trim_multiline("\t...".into(), false, None));
-        assert_eq!("...", trim_multiline("\t\t...".into(), false, None));
+    fn test_reindent_multiline_single_line() {
+        assert_eq!("", reindent_multiline("".into(), false, None));
+        assert_eq!("...", reindent_multiline("...".into(), false, None));
+        assert_eq!("...", reindent_multiline("    ...".into(), false, None));
+        assert_eq!("...", reindent_multiline("\t...".into(), false, None));
+        assert_eq!("...", reindent_multiline("\t\t...".into(), false, None));
     }
 
     #[test]
     #[rustfmt::skip]
-    fn test_trim_multiline_block() {
+    fn test_reindent_multiline_block() {
         assert_eq!("\
     if x {
         y
     } else {
         z
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
             y
         } else {
             z
@@ -1503,7 +1489,7 @@ mod test {
     \ty
     } else {
     \tz
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
         \ty
         } else {
         \tz
@@ -1512,14 +1498,14 @@ mod test {
 
     #[test]
     #[rustfmt::skip]
-    fn test_trim_multiline_empty_line() {
+    fn test_reindent_multiline_empty_line() {
         assert_eq!("\
     if x {
         y
 
     } else {
         z
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
             y
 
         } else {
@@ -1528,6 +1514,22 @@ mod test {
     }
 
     #[test]
+    #[rustfmt::skip]
+    fn test_reindent_multiline_lines_deeper() {
+        assert_eq!("\
+        if x {
+            y
+        } else {
+            z
+        }", reindent_multiline("\
+    if x {
+        y
+    } else {
+        z
+    }".into(), true, Some(8)));
+    }
+
+    #[test]
     fn test_without_block_comments_lines_without_block_comments() {
         let result = without_block_comments(vec!["/*", "", "*/"]);
         println!("result: {:?}", result);
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 9837759fd5e..edf070aaf3b 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -109,14 +109,19 @@ pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWrite
 pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
-pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
+pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
+pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
 pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
 pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
+pub const STRING: [&str; 3] = ["alloc", "string", "String"];
 pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
 pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
+pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
+pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
+pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
 pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
diff --git a/clippy_lints/src/utils/qualify_min_const_fn.rs b/clippy_lints/src/utils/qualify_min_const_fn.rs
new file mode 100644
index 00000000000..3773b9d9a2e
--- /dev/null
+++ b/clippy_lints/src/utils/qualify_min_const_fn.rs
@@ -0,0 +1,347 @@
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::{
+    Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
+    TerminatorKind,
+};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi::RustIntrinsic;
+use std::borrow::Cow;
+
+type McfResult = Result<(), (Span, Cow<'static, str>)>;
+
+pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult {
+    let mut current = def_id;
+    loop {
+        let predicates = tcx.predicates_of(current);
+        for (predicate, _) in predicates.predicates {
+            match predicate.skip_binders() {
+                ty::PredicateAtom::RegionOutlives(_)
+                | ty::PredicateAtom::TypeOutlives(_)
+                | ty::PredicateAtom::WellFormed(_)
+                | ty::PredicateAtom::Projection(_)
+                | ty::PredicateAtom::ConstEvaluatable(..)
+                | ty::PredicateAtom::ConstEquate(..)
+                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
+                ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::Trait(pred, _) => {
+                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
+                        continue;
+                    }
+                    match pred.self_ty().kind() {
+                        ty::Param(ref p) => {
+                            let generics = tcx.generics_of(current);
+                            let def = generics.type_param(p, tcx);
+                            let span = tcx.def_span(def.def_id);
+                            return Err((
+                                span,
+                                "trait bounds other than `Sized` \
+                                 on const fn parameters are unstable"
+                                    .into(),
+                            ));
+                        },
+                        // other kinds of bounds are either tautologies
+                        // or cause errors in other passes
+                        _ => continue,
+                    }
+                },
+            }
+        }
+        match predicates.parent {
+            Some(parent) => current = parent,
+            None => break,
+        }
+    }
+
+    for local in &body.local_decls {
+        check_ty(tcx, local.ty, local.source_info.span)?;
+    }
+    // impl trait is gone in MIR, so check the return type manually
+    check_ty(
+        tcx,
+        tcx.fn_sig(def_id).output().skip_binder(),
+        body.local_decls.iter().next().unwrap().source_info.span,
+    )?;
+
+    for bb in body.basic_blocks() {
+        check_terminator(tcx, body, bb.terminator())?;
+        for stmt in &bb.statements {
+            check_statement(tcx, body, def_id, stmt)?;
+        }
+    }
+    Ok(())
+}
+
+fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
+    for arg in ty.walk() {
+        let ty = match arg.unpack() {
+            GenericArgKind::Type(ty) => ty,
+
+            // No constraints on lifetimes or constants, except potentially
+            // constants' types, but `walk` will get to them as well.
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
+        };
+
+        match ty.kind() {
+            ty::Ref(_, _, hir::Mutability::Mut) => {
+                return Err((span, "mutable references in const fn are unstable".into()));
+            },
+            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+            ty::FnPtr(..) => {
+                return Err((span, "function pointers in const fn are unstable".into()));
+            },
+            ty::Dynamic(preds, _) => {
+                for pred in preds.iter() {
+                    match pred.skip_binder() {
+                        ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
+                            return Err((
+                                span,
+                                "trait bounds other than `Sized` \
+                                 on const fn parameters are unstable"
+                                    .into(),
+                            ));
+                        },
+                        ty::ExistentialPredicate::Trait(trait_ref) => {
+                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
+                                return Err((
+                                    span,
+                                    "trait bounds other than `Sized` \
+                                     on const fn parameters are unstable"
+                                        .into(),
+                                ));
+                            }
+                        },
+                    }
+                }
+            },
+            _ => {},
+        }
+    }
+    Ok(())
+}
+
+fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult {
+    match rvalue {
+        Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
+        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
+            check_place(tcx, *place, span, body)
+        },
+        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
+            use rustc_middle::ty::cast::CastTy;
+            let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
+            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+            match (cast_in, cast_out) {
+                (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
+                    Err((span, "casting pointers to ints is unstable in const fn".into()))
+                },
+                _ => check_operand(tcx, operand, span, body),
+            }
+        },
+        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
+            check_operand(tcx, operand, span, body)
+        },
+        Rvalue::Cast(
+            CastKind::Pointer(
+                PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
+            ),
+            _,
+            _,
+        ) => Err((span, "function pointer casts are not allowed in const fn".into())),
+        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => {
+            let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
+                deref_ty.ty
+            } else {
+                // We cannot allow this for now.
+                return Err((span, "unsizing casts are only allowed for references right now".into()));
+            };
+            let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
+            if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
+                check_operand(tcx, op, span, body)?;
+                // Casting/coercing things to slices is fine.
+                Ok(())
+            } else {
+                // We just can't allow trait objects until we have figured out trait method calls.
+                Err((span, "unsizing casts are not allowed in const fn".into()))
+            }
+        },
+        // binops are fine on integers
+        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
+            check_operand(tcx, lhs, span, body)?;
+            check_operand(tcx, rhs, span, body)?;
+            let ty = lhs.ty(body, tcx);
+            if ty.is_integral() || ty.is_bool() || ty.is_char() {
+                Ok(())
+            } else {
+                Err((
+                    span,
+                    "only int, `bool` and `char` operations are stable in const fn".into(),
+                ))
+            }
+        },
+        Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
+        Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
+        Rvalue::UnaryOp(_, operand) => {
+            let ty = operand.ty(body, tcx);
+            if ty.is_integral() || ty.is_bool() {
+                check_operand(tcx, operand, span, body)
+            } else {
+                Err((span, "only int and `bool` operations are stable in const fn".into()))
+            }
+        },
+        Rvalue::Aggregate(_, operands) => {
+            for operand in operands {
+                check_operand(tcx, operand, span, body)?;
+            }
+            Ok(())
+        },
+    }
+}
+
+fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult {
+    let span = statement.source_info.span;
+    match &statement.kind {
+        StatementKind::Assign(box (place, rval)) => {
+            check_place(tcx, *place, span, body)?;
+            check_rvalue(tcx, body, def_id, rval, span)
+        },
+
+        StatementKind::FakeRead(_, place) |
+        // just an assignment
+        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
+
+        StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
+
+        // These are all NOPs
+        StatementKind::StorageLive(_)
+        | StatementKind::StorageDead(_)
+        | StatementKind::Retag { .. }
+        | StatementKind::AscribeUserType(..)
+        | StatementKind::Coverage(..)
+        | StatementKind::Nop => Ok(()),
+    }
+}
+
+fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+    match operand {
+        Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
+        Operand::Constant(c) => match c.check_static_ptr(tcx) {
+            Some(_) => Err((span, "cannot access `static` items in const fn".into())),
+            None => Ok(()),
+        },
+    }
+}
+
+fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+    let mut cursor = place.projection.as_ref();
+    while let [ref proj_base @ .., elem] = *cursor {
+        cursor = proj_base;
+        match elem {
+            ProjectionElem::Field(..) => {
+                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() {
+                        return Err((span, "accessing union fields is unstable".into()));
+                    }
+                }
+            },
+            ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Downcast(..)
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Deref
+            | ProjectionElem::Index(_) => {},
+        }
+    }
+
+    Ok(())
+}
+
+fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult {
+    let span = terminator.source_info.span;
+    match &terminator.kind {
+        TerminatorKind::FalseEdge { .. }
+        | TerminatorKind::FalseUnwind { .. }
+        | TerminatorKind::Goto { .. }
+        | TerminatorKind::Return
+        | TerminatorKind::Resume
+        | TerminatorKind::Unreachable => Ok(()),
+
+        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
+        TerminatorKind::DropAndReplace { place, value, .. } => {
+            check_place(tcx, *place, span, body)?;
+            check_operand(tcx, value, span, body)
+        },
+
+        TerminatorKind::SwitchInt {
+            discr,
+            switch_ty: _,
+            values: _,
+            targets: _,
+        } => check_operand(tcx, discr, span, body),
+
+        TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
+        TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
+            Err((span, "const fn generators are unstable".into()))
+        },
+
+        TerminatorKind::Call {
+            func,
+            args,
+            from_hir_call: _,
+            destination: _,
+            cleanup: _,
+            fn_span: _,
+        } => {
+            let fn_ty = func.ty(body, tcx);
+            if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
+                if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) {
+                    return Err((
+                        span,
+                        format!(
+                            "can only call other `const fn` within a `const fn`, \
+                             but `{:?}` is not stable as `const fn`",
+                            func,
+                        )
+                        .into(),
+                    ));
+                }
+
+                // HACK: This is to "unstabilize" the `transmute` intrinsic
+                // within const fns. `transmute` is allowed in all other const contexts.
+                // This won't really scale to more intrinsics or functions. Let's allow const
+                // transmutes in const fn before we add more hacks to this.
+                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute {
+                    return Err((
+                        span,
+                        "can only call `transmute` from const items, not `const fn`".into(),
+                    ));
+                }
+
+                check_operand(tcx, func, span, body)?;
+
+                for arg in args {
+                    check_operand(tcx, arg, span, body)?;
+                }
+                Ok(())
+            } else {
+                Err((span, "can only call other const fns within const fn".into()))
+            }
+        },
+
+        TerminatorKind::Assert {
+            cond,
+            expected: _,
+            msg: _,
+            target: _,
+            cleanup: _,
+        } => check_operand(tcx, cond, span, body),
+
+        TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
+    }
+}
diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs
index 811fde388d1..ec8b7e59b59 100644
--- a/clippy_lints/src/utils/sugg.rs
+++ b/clippy_lints/src/utils/sugg.rs
@@ -49,7 +49,7 @@ impl<'a> Sugg<'a> {
     /// Convenience function around `hir_opt` for suggestions with a default
     /// text.
     pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
-        Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default)))
+        Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default)))
     }
 
     /// Same as `hir`, but it adapts the applicability level by following rules:
diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs
index 4a64b935ac9..ea1dc3be29b 100644
--- a/clippy_lints/src/utils/usage.rs
+++ b/clippy_lints/src/utils/usage.rs
@@ -1,6 +1,8 @@
 use crate::utils::match_var;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
 use rustc_hir::def::Res;
+use rustc_hir::intravisit;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Expr, HirId, Path};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -108,3 +110,67 @@ pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool {
     walk_expr(&mut visitor, body);
     !visitor.used
 }
+
+pub struct ParamBindingIdCollector {
+    binding_hir_ids: Vec<hir::HirId>,
+}
+impl<'tcx> ParamBindingIdCollector {
+    fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
+        let mut finder = ParamBindingIdCollector {
+            binding_hir_ids: Vec::new(),
+        };
+        finder.visit_body(body);
+        finder.binding_hir_ids
+    }
+}
+impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
+    type Map = Map<'tcx>;
+
+    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+        if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind {
+            self.binding_hir_ids.push(hir_id);
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::None
+    }
+}
+
+pub struct BindingUsageFinder<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    binding_ids: Vec<hir::HirId>,
+    usage_found: bool,
+}
+impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
+    pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool {
+        let mut finder = BindingUsageFinder {
+            cx,
+            binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body),
+            usage_found: false,
+        };
+        finder.visit_body(body);
+        finder.usage_found
+    }
+}
+impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        if !self.usage_found {
+            intravisit::walk_expr(self, expr);
+        }
+    }
+
+    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
+        if let hir::def::Res::Local(id) = path.res {
+            if self.binding_ids.contains(&id) {
+                self.usage_found = true;
+            }
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    }
+}
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index e653240d049..d9d60fffcd7 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -235,8 +235,19 @@ impl EarlyLintPass for Write {
     }
 
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
+        fn is_build_script(cx: &EarlyContext<'_>) -> bool {
+            // Cargo sets the crate name for build scripts to `build_script_build`
+            cx.sess
+                .opts
+                .crate_name
+                .as_ref()
+                .map_or(false, |crate_name| crate_name == "build_script_build")
+        }
+
         if mac.path == sym!(println) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if fmt_str.symbol == Symbol::intern("") {
                     span_lint_and_sugg(
@@ -251,7 +262,9 @@ impl EarlyLintPass for Write {
                 }
             }
         } else if mac.path == sym!(print) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if check_newlines(&fmt_str) {
                     span_lint_and_then(
@@ -322,11 +335,15 @@ impl EarlyLintPass for Write {
 }
 
 /// Given a format string that ends in a newline and its span, calculates the span of the
-/// newline.
+/// newline, or the format string itself if the format string consists solely of a newline.
 fn newline_span(fmtstr: &StrLit) -> Span {
     let sp = fmtstr.span;
     let contents = &fmtstr.symbol.as_str();
 
+    if *contents == r"\n" {
+        return sp;
+    }
+
     let newline_sp_hi = sp.hi()
         - match fmtstr.style {
             StrStyle::Cooked => BytePos(1),
diff --git a/clippy_workspace_tests/build.rs b/clippy_workspace_tests/build.rs
new file mode 100644
index 00000000000..3507168a3a9
--- /dev/null
+++ b/clippy_workspace_tests/build.rs
@@ -0,0 +1,7 @@
+#![deny(clippy::print_stdout)]
+
+fn main() {
+    // Test for #6041
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/doc/adding_lints.md b/doc/adding_lints.md
index 3c782e9b17f..21e0f6f4fc7 100644
--- a/doc/adding_lints.md
+++ b/doc/adding_lints.md
@@ -488,7 +488,7 @@ For `LateLintPass` lints:
 While most of Clippy's lint utils are documented, most of rustc's internals lack
 documentation currently. This is unfortunate, but in most cases you can probably
 get away with copying things from existing similar lints. If you are stuck,
-don't hesitate to ask on [Discord] or in the issue/PR.
+don't hesitate to ask on [Zulip] or in the issue/PR.
 
 [utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
 [if_chain]: https://docs.rs/if_chain/*/if_chain/
@@ -500,4 +500,4 @@ don't hesitate to ask on [Discord] or in the issue/PR.
 [nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
 [ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
 [ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/index.html
-[Discord]: https://discord.gg/rust-lang
+[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md
index 9dd4c8a5f7a..53c3d084dbc 100644
--- a/doc/common_tools_writing_lints.md
+++ b/doc/common_tools_writing_lints.md
@@ -60,7 +60,7 @@ impl LateLintPass<'_> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             // Check our expr is calling a method
-            if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind;
+            if let hir::ExprKind::MethodCall(path, _, _args, _) = &expr.kind;
             // Check the name of this method is `some_method`
             if path.ident.name == sym!(some_method);
             then {
diff --git a/src/driver.rs b/src/driver.rs
index 47315fa64cd..f4f2259cefd 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -357,7 +357,7 @@ pub fn main() {
                 args.extend(vec!["--sysroot".into(), sys_root]);
             };
 
-            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None, None);
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -420,6 +420,6 @@ pub fn main() {
         let mut default = DefaultCallbacks;
         let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
             if clippy_enabled { &mut clippy } else { &mut default };
-        rustc_driver::run_compiler(&args, callbacks, None, None)
+        rustc_driver::run_compiler(&args, callbacks, None, None, None)
     }))
 }
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index dff19ef440f..76e655ad603 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -298,6 +298,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "copy_iterator",
     },
     Lint {
+        name: "create_dir",
+        group: "restriction",
+        desc: "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`",
+        deprecation: None,
+        module: "create_dir",
+    },
+    Lint {
         name: "crosspointer_transmute",
         group: "complexity",
         desc: "transmutes that have to or from types that are a pointer to the other",
@@ -375,6 +382,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "derive",
     },
     Lint {
+        name: "disallowed_method",
+        group: "nursery",
+        desc: "use of a disallowed method call",
+        deprecation: None,
+        module: "disallowed_method",
+    },
+    Lint {
         name: "diverging_sub_expression",
         group: "complexity",
         desc: "whether an expression contains a diverging sub expression",
@@ -923,7 +937,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     Lint {
         name: "invalid_atomic_ordering",
         group: "correctness",
-        desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences",
+        desc: "usage of invalid atomic ordering in atomic operations and memory fences",
         deprecation: None,
         module: "atomic_ordering",
     },
@@ -1138,6 +1152,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "methods",
     },
     Lint {
+        name: "manual_strip",
+        group: "complexity",
+        desc: "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing",
+        deprecation: None,
+        module: "manual_strip",
+    },
+    Lint {
         name: "manual_swap",
         group: "complexity",
         desc: "manual swap of two variables",
@@ -1166,6 +1187,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "entry",
     },
     Lint {
+        name: "map_err_ignore",
+        group: "pedantic",
+        desc: "`map_err` should not ignore the original error",
+        deprecation: None,
+        module: "map_err_ignore",
+    },
+    Lint {
         name: "map_flatten",
         group: "pedantic",
         desc: "using combinations of `flatten` and `map` which can usually be written as a single method call",
@@ -1712,6 +1740,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "panic_unimplemented",
     },
     Lint {
+        name: "panic_in_result_fn",
+        group: "restriction",
+        desc: "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` ",
+        deprecation: None,
+        module: "panic_in_result_fn",
+    },
+    Lint {
         name: "panic_params",
         group: "style",
         desc: "missing parameters in `panic!` calls",
@@ -1838,6 +1873,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "ranges",
     },
     Lint {
+        name: "rc_buffer",
+        group: "perf",
+        desc: "shared ownership of a buffer type",
+        deprecation: None,
+        module: "types",
+    },
+    Lint {
         name: "redundant_allocation",
         group: "perf",
         desc: "redundant allocation",
@@ -2623,7 +2665,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "verbose_bit_mask",
-        group: "style",
+        group: "pedantic",
         desc: "expressions where a bit mask is less readable than the corresponding method call",
         deprecation: None,
         module: "bit_mask",
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index 697823712bf..f0d73e9b0e2 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -71,7 +71,7 @@ fn default_config() -> compiletest::Config {
     }
 
     config.target_rustcflags = Some(format!(
-        "-L {0} -L {1} -Dwarnings -Zui-testing {2}",
+        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
         host_lib().join("deps").display(),
         cargo::TARGET_LIB.join("deps").display(),
         third_party_crates(),
diff --git a/tests/ui-toml/toml_disallowed_method/clippy.toml b/tests/ui-toml/toml_disallowed_method/clippy.toml
new file mode 100644
index 00000000000..a1f515e443d
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/clippy.toml
@@ -0,0 +1 @@
+disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
new file mode 100644
index 00000000000..3d3f0729abd
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::disallowed_method)]
+
+extern crate regex;
+use regex::Regex;
+
+fn main() {
+    let a = vec![1, 2, 3, 4];
+    let re = Regex::new(r"ab.*c").unwrap();
+
+    re.is_match("abc");
+
+    a.iter().sum::<i32>();
+}
diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
new file mode 100644
index 00000000000..ed91b5a6796
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
@@ -0,0 +1,16 @@
+error: use of a disallowed method `regex::re_unicode::Regex::is_match`
+  --> $DIR/conf_disallowed_method.rs:10:5
+   |
+LL |     re.is_match("abc");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::disallowed-method` implied by `-D warnings`
+
+error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
+  --> $DIR/conf_disallowed_method.rs:12:5
+   |
+LL |     a.iter().sum::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6fbba01416a..103ec27e7d7 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `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`, `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`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `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`, `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`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/tests/ui/atomic_ordering_exchange.rs b/tests/ui/atomic_ordering_exchange.rs
new file mode 100644
index 00000000000..1ddc12f9ab2
--- /dev/null
+++ b/tests/ui/atomic_ordering_exchange.rs
@@ -0,0 +1,45 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+fn main() {
+    // `compare_exchange` (not weak) testing
+    let x = AtomicUsize::new(0);
+
+    // Allowed ordering combos
+    let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Relaxed);
+    let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Acquire);
+    let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Relaxed);
+    let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Relaxed);
+    let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Acquire);
+    let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Relaxed);
+    let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Relaxed);
+    let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Acquire);
+    let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::SeqCst);
+
+    // AcqRel is always forbidden as a failure ordering
+    let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel);
+    let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel);
+    let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel);
+    let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel);
+    let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel);
+
+    // Release is always forbidden as a failure ordering
+    let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release);
+    let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release);
+    let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release);
+    let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release);
+    let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release);
+
+    // Release success order forbids failure order of Acquire or SeqCst
+    let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire);
+    let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst);
+
+    // Relaxed success order also forbids failure order of Acquire or SeqCst
+    let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst);
+    let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire);
+
+    // Acquire/AcqRel forbids failure order of SeqCst
+    let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst);
+    let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst);
+}
diff --git a/tests/ui/atomic_ordering_exchange.stderr b/tests/ui/atomic_ordering_exchange.stderr
new file mode 100644
index 00000000000..4b9bfef7974
--- /dev/null
+++ b/tests/ui/atomic_ordering_exchange.stderr
@@ -0,0 +1,131 @@
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:21:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:22:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:23:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:24:56
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel);
+   |                                                        ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:25:56
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel);
+   |                                                        ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:28:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release);
+   |                                                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:29:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release);
+   |                                                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:30:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release);
+   |                                                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:31:56
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release);
+   |                                                        ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:32:56
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release);
+   |                                                        ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_exchange.rs:35:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire);
+   |                                                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_exchange.rs:36:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_exchange.rs:39:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_exchange.rs:40:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire);
+   |                                                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `Acquire`
+  --> $DIR/atomic_ordering_exchange.rs:43:57
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst);
+   |                                                         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange's failure ordering may not be stronger than the success ordering of `AcqRel`
+  --> $DIR/atomic_ordering_exchange.rs:44:56
+   |
+LL |     let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst);
+   |                                                        ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/atomic_ordering_exchange_weak.rs b/tests/ui/atomic_ordering_exchange_weak.rs
new file mode 100644
index 00000000000..59069902507
--- /dev/null
+++ b/tests/ui/atomic_ordering_exchange_weak.rs
@@ -0,0 +1,47 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+fn main() {
+    let ptr = &mut 5;
+    let ptr2 = &mut 10;
+    // `compare_exchange_weak` testing
+    let x = AtomicPtr::new(ptr);
+
+    // Allowed ordering combos
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Relaxed);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Acquire);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Relaxed);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Relaxed);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Acquire);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Relaxed);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Relaxed);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Acquire);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::SeqCst);
+
+    // AcqRel is always forbidden as a failure ordering
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel);
+
+    // Release is always forbidden as a failure ordering
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release);
+
+    // Release success order forbids failure order of Acquire or SeqCst
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst);
+
+    // Relaxed success order also forbids failure order of Acquire or SeqCst
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst);
+    let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire);
+
+    // Acquire/AcqRel forbids failure order of SeqCst
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst);
+    let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst);
+}
diff --git a/tests/ui/atomic_ordering_exchange_weak.stderr b/tests/ui/atomic_ordering_exchange_weak.stderr
new file mode 100644
index 00000000000..de7026f3ffa
--- /dev/null
+++ b/tests/ui/atomic_ordering_exchange_weak.stderr
@@ -0,0 +1,131 @@
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:23:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:24:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:25:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:26:66
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel);
+   |                                                                  ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:27:66
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel);
+   |                                                                  ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:30:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release);
+   |                                                                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:31:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release);
+   |                                                                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:32:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release);
+   |                                                                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:33:66
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release);
+   |                                                                  ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:34:66
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release);
+   |                                                                  ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_exchange_weak.rs:37:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire);
+   |                                                                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_exchange_weak.rs:38:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_exchange_weak.rs:41:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_exchange_weak.rs:42:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire);
+   |                                                                   ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Acquire`
+  --> $DIR/atomic_ordering_exchange_weak.rs:45:67
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst);
+   |                                                                   ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `AcqRel`
+  --> $DIR/atomic_ordering_exchange_weak.rs:46:66
+   |
+LL |     let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst);
+   |                                                                  ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/atomic_ordering_fetch_update.rs b/tests/ui/atomic_ordering_fetch_update.rs
new file mode 100644
index 00000000000..550bdb001e4
--- /dev/null
+++ b/tests/ui/atomic_ordering_fetch_update.rs
@@ -0,0 +1,45 @@
+#![warn(clippy::invalid_atomic_ordering)]
+
+use std::sync::atomic::{AtomicIsize, Ordering};
+
+fn main() {
+    // `fetch_update` testing
+    let x = AtomicIsize::new(0);
+
+    // Allowed ordering combos
+    let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1));
+
+    // AcqRel is always forbidden as a failure ordering
+    let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
+
+    // Release is always forbidden as a failure ordering
+    let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
+
+    // Release success order forbids failure order of Acquire or SeqCst
+    let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
+
+    // Relaxed success order also forbids failure order of Acquire or SeqCst
+    let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
+
+    // Acquire/AcqRel forbids failure order of SeqCst
+    let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
+    let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
+}
diff --git a/tests/ui/atomic_ordering_fetch_update.stderr b/tests/ui/atomic_ordering_fetch_update.stderr
new file mode 100644
index 00000000000..694548ece97
--- /dev/null
+++ b/tests/ui/atomic_ordering_fetch_update.stderr
@@ -0,0 +1,131 @@
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:21:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:22:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:23:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:24:46
+   |
+LL |     let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
+   |                                              ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:25:46
+   |
+LL |     let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
+   |                                              ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:28:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:29:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:30:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:31:46
+   |
+LL |     let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
+   |                                              ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be `Release` or `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:32:46
+   |
+LL |     let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
+   |                                              ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_fetch_update.rs:35:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Release`
+  --> $DIR/atomic_ordering_fetch_update.rs:36:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_fetch_update.rs:39:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed`
+  --> $DIR/atomic_ordering_fetch_update.rs:40:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering mode `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `Acquire`
+  --> $DIR/atomic_ordering_fetch_update.rs:43:47
+   |
+LL |     let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
+   |                                               ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: fetch_update's failure ordering may not be stronger than the success ordering of `AcqRel`
+  --> $DIR/atomic_ordering_fetch_update.rs:44:46
+   |
+LL |     let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
+   |                                              ^^^^^^^^^^^^^^^^
+   |
+   = help: consider using ordering modes `Acquire` or `Relaxed` instead
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs
index e6626d57a77..de670cdfc31 100644
--- a/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/tests/ui/auxiliary/proc_macro_attr.rs
@@ -1,7 +1,8 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
+#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
 #![allow(clippy::useless_conversion)]
 
 extern crate proc_macro;
@@ -11,7 +12,11 @@ extern crate syn;
 use proc_macro::TokenStream;
 use quote::{quote, quote_spanned};
 use syn::parse_macro_input;
-use syn::{parse_quote, ItemTrait, TraitItem};
+use syn::spanned::Spanned;
+use syn::token::Star;
+use syn::{
+    parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
+};
 
 #[proc_macro_attribute]
 pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
@@ -35,3 +40,56 @@ pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
     }
     TokenStream::from(quote!(#item))
 }
+
+#[proc_macro_attribute]
+pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream {
+    fn make_name(count: usize) -> String {
+        format!("'life{}", count)
+    }
+
+    fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
+        let arg = sig.inputs.first_mut()?;
+        if let FnArg::Typed(PatType { pat, .. }) = arg {
+            if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
+                if ident == "self" {
+                    return Some(arg);
+                }
+            }
+        }
+        None
+    }
+
+    let mut elided = 0;
+    let mut item = parse_macro_input!(input as ItemImpl);
+
+    // Look for methods having arbitrary self type taken by &mut ref
+    for inner in &mut item.items {
+        if let ImplItem::Method(method) = inner {
+            if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
+                if let box Type::Reference(reference) = &mut pat_type.ty {
+                    // Target only unnamed lifetimes
+                    let name = match &reference.lifetime {
+                        Some(lt) if lt.ident == "_" => make_name(elided),
+                        None => make_name(elided),
+                        _ => continue,
+                    };
+                    elided += 1;
+
+                    // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
+                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // A default span is needed to mark the code as coming from expansion.
+                    let span = Star::default().span();
+
+                    // Replace old lifetime with the named one
+                    let lifetime = Lifetime::new(&name, span);
+                    reference.lifetime = Some(parse_quote!(#lifetime));
+
+                    // Add lifetime to the generics of the method
+                    method.sig.generics.params.push(parse_quote!(#lifetime));
+                }
+            }
+        }
+    }
+
+    TokenStream::from(quote!(#item))
+}
diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs
index 05ffb55f620..3df8be6c232 100644
--- a/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/tests/ui/auxiliary/proc_macro_derive.rs
@@ -1,3 +1,4 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs
index a414832bcd3..9fcc9ece49b 100644
--- a/tests/ui/borrow_interior_mutable_const.rs
+++ b/tests/ui/borrow_interior_mutable_const.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::borrow_interior_mutable_const)]
 #![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
+#![allow(const_item_mutation)]
 
 use std::borrow::Cow;
 use std::cell::{Cell, UnsafeCell};
@@ -18,16 +19,30 @@ const NO_ANN: &dyn Display = &70;
 static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
 const ONCE_INIT: Once = Once::new();
 
-trait Trait<T>: Copy {
-    type NonCopyType;
+trait Trait<T> {
+    type AssocType;
 
     const ATOMIC: AtomicUsize;
+    const INPUT: T;
+    const ASSOC: Self::AssocType;
+
+    fn function() {
+        let _ = &Self::INPUT;
+        let _ = &Self::ASSOC;
+    }
 }
 
 impl Trait<u32> for u64 {
-    type NonCopyType = u16;
+    type AssocType = AtomicUsize;
 
     const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+    const INPUT: u32 = 10;
+    const ASSOC: Self::AssocType = AtomicUsize::new(11);
+
+    fn function() {
+        let _ = &Self::INPUT;
+        let _ = &Self::ASSOC; //~ ERROR interior mutability
+    }
 }
 
 // This is just a pointer that can be safely dereferended,
diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr
index 1e0b3e4d20a..ed726a6b46e 100644
--- a/tests/ui/borrow_interior_mutable_const.stderr
+++ b/tests/ui/borrow_interior_mutable_const.stderr
@@ -1,14 +1,22 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:65:5
+  --> $DIR/borrow_interior_mutable_const.rs:44:18
+   |
+LL |         let _ = &Self::ASSOC; //~ ERROR interior mutability
+   |                  ^^^^^^^^^^^
+   |
+   = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> $DIR/borrow_interior_mutable_const.rs:80:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^
    |
-   = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:66:16
+  --> $DIR/borrow_interior_mutable_const.rs:81:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
    |                ^^^^^^
@@ -16,7 +24,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:69:22
+  --> $DIR/borrow_interior_mutable_const.rs:84:22
    |
 LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    |                      ^^^^^^^^^
@@ -24,7 +32,7 @@ LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:70:25
+  --> $DIR/borrow_interior_mutable_const.rs:85:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    |                         ^^^^^^^^^
@@ -32,7 +40,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:71:27
+  --> $DIR/borrow_interior_mutable_const.rs:86:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    |                           ^^^^^^^^^
@@ -40,7 +48,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:72:26
+  --> $DIR/borrow_interior_mutable_const.rs:87:26
    |
 LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    |                          ^^^^^^^^^
@@ -48,7 +56,7 @@ LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:83:14
+  --> $DIR/borrow_interior_mutable_const.rs:98:14
    |
 LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -56,7 +64,7 @@ LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:84:14
+  --> $DIR/borrow_interior_mutable_const.rs:99:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -64,7 +72,7 @@ LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:85:19
+  --> $DIR/borrow_interior_mutable_const.rs:100:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    |                   ^^^^^^^^^^^^
@@ -72,7 +80,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:86:14
+  --> $DIR/borrow_interior_mutable_const.rs:101:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -80,7 +88,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:87:13
+  --> $DIR/borrow_interior_mutable_const.rs:102:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -88,7 +96,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:93:13
+  --> $DIR/borrow_interior_mutable_const.rs:108:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -96,7 +104,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:98:5
+  --> $DIR/borrow_interior_mutable_const.rs:113:5
    |
 LL |     CELL.set(2); //~ ERROR interior mutability
    |     ^^^^
@@ -104,7 +112,7 @@ LL |     CELL.set(2); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:99:16
+  --> $DIR/borrow_interior_mutable_const.rs:114:16
    |
 LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    |                ^^^^
@@ -112,7 +120,7 @@ LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:112:5
+  --> $DIR/borrow_interior_mutable_const.rs:127:5
    |
 LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^^^^^^
@@ -120,12 +128,12 @@ LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:113:16
+  --> $DIR/borrow_interior_mutable_const.rs:128:16
    |
 LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
    |                ^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
-error: aborting due to 16 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/crashes/associated-constant-ice.rs b/tests/ui/crashes/associated-constant-ice.rs
index 4bb833795bb..948deba3ea6 100644
--- a/tests/ui/crashes/associated-constant-ice.rs
+++ b/tests/ui/crashes/associated-constant-ice.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1698
 
 pub trait Trait {
diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs
index 086548e58ed..619d11cefc4 100644
--- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs
+++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -1,3 +1,4 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
 // crates. If we don't set this, compiletest will override the `crate_type` attribute below and
diff --git a/tests/ui/crashes/cc_seme.rs b/tests/ui/crashes/cc_seme.rs
index c48c7e9e6c6..98588be9cf8 100644
--- a/tests/ui/crashes/cc_seme.rs
+++ b/tests/ui/crashes/cc_seme.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/478
diff --git a/tests/ui/crashes/enum-glob-import-crate.rs b/tests/ui/crashes/enum-glob-import-crate.rs
index db1fa871afe..dca32aa3b56 100644
--- a/tests/ui/crashes/enum-glob-import-crate.rs
+++ b/tests/ui/crashes/enum-glob-import-crate.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 #![allow(unused_imports)]
 
diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs
index 15d0f705b36..b0a3d11bce4 100644
--- a/tests/ui/crashes/ice-1588.rs
+++ b/tests/ui/crashes/ice-1588.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/tests/ui/crashes/ice-1782.rs b/tests/ui/crashes/ice-1782.rs
index 1ca6b6976b3..81af88962a6 100644
--- a/tests/ui/crashes/ice-1782.rs
+++ b/tests/ui/crashes/ice-1782.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs
index 837ec9df31a..96a8fe6c24d 100644
--- a/tests/ui/crashes/ice-1969.rs
+++ b/tests/ui/crashes/ice-1969.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1969
diff --git a/tests/ui/crashes/ice-2499.rs b/tests/ui/crashes/ice-2499.rs
index ffef1631775..45b3b1869dd 100644
--- a/tests/ui/crashes/ice-2499.rs
+++ b/tests/ui/crashes/ice-2499.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/tests/ui/crashes/ice-2594.rs b/tests/ui/crashes/ice-2594.rs
index ac19f1976e9..3f3986b6fc6 100644
--- a/tests/ui/crashes/ice-2594.rs
+++ b/tests/ui/crashes/ice-2594.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/tests/ui/crashes/ice-2636.rs b/tests/ui/crashes/ice-2636.rs
deleted file mode 100644
index e0b58157590..00000000000
--- a/tests/ui/crashes/ice-2636.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-#![allow(dead_code)]
-
-enum Foo {
-    A,
-    B,
-    C,
-}
-
-macro_rules! test_hash {
-    ($foo:expr, $($t:ident => $ord:expr),+ ) => {
-        use self::Foo::*;
-        match $foo {
-            $ ( & $t => $ord,
-            )*
-        };
-    };
-}
-
-fn main() {
-    let a = Foo::A;
-    test_hash!(&a, A => 0, B => 1, C => 2);
-}
diff --git a/tests/ui/crashes/ice-2636.stderr b/tests/ui/crashes/ice-2636.stderr
deleted file mode 100644
index 53799b4fbf1..00000000000
--- a/tests/ui/crashes/ice-2636.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/ice-2636.rs:12:9
-   |
-LL | /         match $foo {
-LL | |             $ ( & $t => $ord,
-LL | |             )*
-LL | |         };
-   | |_________^
-...
-LL |       test_hash!(&a, A => 0, B => 1, C => 2);
-   |       --------------------------------------- in this macro invocation
-   |
-   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
diff --git a/tests/ui/crashes/ice-2727.rs b/tests/ui/crashes/ice-2727.rs
index d832c286033..56024abc8f5 100644
--- a/tests/ui/crashes/ice-2727.rs
+++ b/tests/ui/crashes/ice-2727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2727
 
 pub fn f(new: fn()) {
diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs
index 9e5e299c336..f1a229f3f4f 100644
--- a/tests/ui/crashes/ice-2760.rs
+++ b/tests/ui/crashes/ice-2760.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(
     unused_variables,
     clippy::blacklisted_name,
diff --git a/tests/ui/crashes/ice-2774.rs b/tests/ui/crashes/ice-2774.rs
index 47f8e3b18ee..d44b0fae820 100644
--- a/tests/ui/crashes/ice-2774.rs
+++ b/tests/ui/crashes/ice-2774.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 use std::collections::HashSet;
 
 // See rust-lang/rust-clippy#2774.
diff --git a/tests/ui/crashes/ice-2862.rs b/tests/ui/crashes/ice-2862.rs
index 47324ce1831..8326e3663b0 100644
--- a/tests/ui/crashes/ice-2862.rs
+++ b/tests/ui/crashes/ice-2862.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2862
 
 pub trait FooMap {
diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs
index c4f6c0fed68..6b1ceb50569 100644
--- a/tests/ui/crashes/ice-2865.rs
+++ b/tests/ui/crashes/ice-2865.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs
index ffad2d06b56..fef4d7db84d 100644
--- a/tests/ui/crashes/ice-3151.rs
+++ b/tests/ui/crashes/ice-3151.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
 
 #[derive(Clone)]
diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs
index 95c7dff9be3..7d62e315da2 100644
--- a/tests/ui/crashes/ice-3462.rs
+++ b/tests/ui/crashes/ice-3462.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::all)]
 #![allow(clippy::blacklisted_name)]
 #![allow(unused)]
diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs
index a548415da62..1253ddcfaeb 100644
--- a/tests/ui/crashes/ice-3741.rs
+++ b/tests/ui/crashes/ice-3741.rs
@@ -1,5 +1,4 @@
 // aux-build:proc_macro_crash.rs
-// run-pass
 
 #![warn(clippy::suspicious_else_formatting)]
 
diff --git a/tests/ui/crashes/ice-3747.rs b/tests/ui/crashes/ice-3747.rs
index d0b44ebafee..cdf018cbc88 100644
--- a/tests/ui/crashes/ice-3747.rs
+++ b/tests/ui/crashes/ice-3747.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/3747
 
 macro_rules! a {
diff --git a/tests/ui/crashes/ice-4727.rs b/tests/ui/crashes/ice-4727.rs
index cdb59caec67..2a4bc83f58a 100644
--- a/tests/ui/crashes/ice-4727.rs
+++ b/tests/ui/crashes/ice-4727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::use_self)]
 
 #[path = "auxiliary/ice-4727-aux.rs"]
diff --git a/tests/ui/crashes/ice-4760.rs b/tests/ui/crashes/ice-4760.rs
index ead67d5ed1b..08b06961760 100644
--- a/tests/ui/crashes/ice-4760.rs
+++ b/tests/ui/crashes/ice-4760.rs
@@ -1,4 +1,3 @@
-// run-pass
 const COUNT: usize = 2;
 struct Thing;
 trait Dummy {}
diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs
index b06df83d51a..0cbceedbd6b 100644
--- a/tests/ui/crashes/ice-700.rs
+++ b/tests/ui/crashes/ice-700.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/700
diff --git a/tests/ui/crashes/ice_exacte_size.rs b/tests/ui/crashes/ice_exacte_size.rs
index e02eb28ab86..30e4b11ec0b 100644
--- a/tests/ui/crashes/ice_exacte_size.rs
+++ b/tests/ui/crashes/ice_exacte_size.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1336
diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs
index 4ef992b05e7..2f913292995 100644
--- a/tests/ui/crashes/if_same_then_else.rs
+++ b/tests/ui/crashes/if_same_then_else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::comparison_chain)]
 #![deny(clippy::if_same_then_else)]
 
diff --git a/tests/ui/crashes/issue-825.rs b/tests/ui/crashes/issue-825.rs
index 3d4a88ab3c4..05696e3d7d5 100644
--- a/tests/ui/crashes/issue-825.rs
+++ b/tests/ui/crashes/issue-825.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(warnings)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/825
diff --git a/tests/ui/crashes/issues_loop_mut_cond.rs b/tests/ui/crashes/issues_loop_mut_cond.rs
index c4acd5cda1b..bb238c81ebc 100644
--- a/tests/ui/crashes/issues_loop_mut_cond.rs
+++ b/tests/ui/crashes/issues_loop_mut_cond.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code)]
 
 /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
diff --git a/tests/ui/crashes/match_same_arms_const.rs b/tests/ui/crashes/match_same_arms_const.rs
index 848f0ea52ca..94c939665e6 100644
--- a/tests/ui/crashes/match_same_arms_const.rs
+++ b/tests/ui/crashes/match_same_arms_const.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::match_same_arms)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2427
diff --git a/tests/ui/crashes/mut_mut_macro.rs b/tests/ui/crashes/mut_mut_macro.rs
index d8fbaa54146..a238e7896fc 100644
--- a/tests/ui/crashes/mut_mut_macro.rs
+++ b/tests/ui/crashes/mut_mut_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
 #![allow(dead_code)]
 
diff --git a/tests/ui/crashes/needless_borrow_fp.rs b/tests/ui/crashes/needless_borrow_fp.rs
index 48507efe1e9..4f61c76828d 100644
--- a/tests/ui/crashes/needless_borrow_fp.rs
+++ b/tests/ui/crashes/needless_borrow_fp.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[deny(clippy::all)]
 #[derive(Debug)]
 pub enum Error {
diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/tests/ui/crashes/needless_lifetimes_impl_trait.rs
index bd1fa4a0b1e..676564b2445 100644
--- a/tests/ui/crashes/needless_lifetimes_impl_trait.rs
+++ b/tests/ui/crashes/needless_lifetimes_impl_trait.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::needless_lifetimes)]
 #![allow(dead_code)]
 
diff --git a/tests/ui/crashes/procedural_macro.rs b/tests/ui/crashes/procedural_macro.rs
index f79d9ab6460..c7468493380 100644
--- a/tests/ui/crashes/procedural_macro.rs
+++ b/tests/ui/crashes/procedural_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[macro_use]
 extern crate clippy_mini_macro_test;
 
diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs
index 3d5063d1a3a..a41bcb33b44 100644
--- a/tests/ui/crashes/regressions.rs
+++ b/tests/ui/crashes/regressions.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::blacklisted_name)]
 
 pub fn foo(bar: *const u8) {
diff --git a/tests/ui/crashes/returns.rs b/tests/ui/crashes/returns.rs
index f2153efc388..8021ed4607d 100644
--- a/tests/ui/crashes/returns.rs
+++ b/tests/ui/crashes/returns.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1346
 
 #[deny(warnings)]
diff --git a/tests/ui/crashes/single-match-else.rs b/tests/ui/crashes/single-match-else.rs
index 3a4bbe310cc..1ba7ac08213 100644
--- a/tests/ui/crashes/single-match-else.rs
+++ b/tests/ui/crashes/single-match-else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::single_match_else)]
 
 //! Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/tests/ui/crashes/trivial_bounds.rs b/tests/ui/crashes/trivial_bounds.rs
index 2bb95c18a39..60105a8213f 100644
--- a/tests/ui/crashes/trivial_bounds.rs
+++ b/tests/ui/crashes/trivial_bounds.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![feature(trivial_bounds)]
 #![allow(unused, trivial_bounds)]
 
diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs
index 265017c51d9..6d2124c12fe 100644
--- a/tests/ui/crashes/used_underscore_binding_macro.rs
+++ b/tests/ui/crashes/used_underscore_binding_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::useless_attribute)] //issue #2910
 
 #[macro_use]
diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed
new file mode 100644
index 00000000000..8ed53a56ac0
--- /dev/null
+++ b/tests/ui/create_dir.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![warn(clippy::create_dir)]
+
+use std::fs::create_dir_all;
+
+fn create_dir() {}
+
+fn main() {
+    // Should be warned
+    create_dir_all("foo");
+    create_dir_all("bar").unwrap();
+
+    // Shouldn't be warned
+    create_dir();
+    std::fs::create_dir_all("foobar");
+}
diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs
new file mode 100644
index 00000000000..19c8fc24ba2
--- /dev/null
+++ b/tests/ui/create_dir.rs
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![warn(clippy::create_dir)]
+
+use std::fs::create_dir_all;
+
+fn create_dir() {}
+
+fn main() {
+    // Should be warned
+    std::fs::create_dir("foo");
+    std::fs::create_dir("bar").unwrap();
+
+    // Shouldn't be warned
+    create_dir();
+    std::fs::create_dir_all("foobar");
+}
diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr
new file mode 100644
index 00000000000..67298fc4709
--- /dev/null
+++ b/tests/ui/create_dir.stderr
@@ -0,0 +1,16 @@
+error: calling `std::fs::create_dir` where there may be a better way
+  --> $DIR/create_dir.rs:11:5
+   |
+LL |     std::fs::create_dir("foo");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")`
+   |
+   = note: `-D clippy::create-dir` implied by `-D warnings`
+
+error: calling `std::fs::create_dir` where there may be a better way
+  --> $DIR/create_dir.rs:12:5
+   |
+LL |     std::fs::create_dir("bar").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs
index b4003ed8932..3afcdca2f04 100644
--- a/tests/ui/declare_interior_mutable_const.rs
+++ b/tests/ui/declare_interior_mutable_const.rs
@@ -34,60 +34,141 @@ static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
 #[allow(clippy::declare_interior_mutable_const)]
 const ONCE_INIT: Once = Once::new();
 
-trait Trait<T>: Copy {
-    type NonCopyType;
-
+// a constant whose type is a concrete type should be linted at the definition site.
+trait ConcreteTypes {
     const ATOMIC: AtomicUsize; //~ ERROR interior mutable
     const INTEGER: u64;
     const STRING: String;
-    const SELF: Self; // (no error)
-    const INPUT: T;
-    //~^ ERROR interior mutable
-    //~| HELP consider requiring `T` to be `Copy`
-    const ASSOC: Self::NonCopyType;
-    //~^ ERROR interior mutable
-    //~| HELP consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+    declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+}
 
-    const AN_INPUT: T = Self::INPUT;
-    //~^ ERROR interior mutable
-    //~| ERROR consider requiring `T` to be `Copy`
-    declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
+impl ConcreteTypes for u64 {
+    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
+    const INTEGER: u64 = 10;
+    const STRING: String = String::new();
 }
 
-trait Trait2 {
-    type CopyType: Copy;
+// a helper trait used below
+trait ConstDefault {
+    const DEFAULT: Self;
+}
+
+// a constant whose type is a generic type should be linted at the implementation site.
+trait GenericTypes<T, U> {
+    const TO_REMAIN_GENERIC: T;
+    const TO_BE_CONCRETE: U;
 
-    const SELF_2: Self;
-    //~^ ERROR interior mutable
-    //~| HELP consider requiring `Self` to be `Copy`
-    const ASSOC_2: Self::CopyType; // (no error)
+    const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
+    declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
 }
 
-// we don't lint impl of traits, because an impl has no power to change the interface.
-impl Trait<u32> for u64 {
-    type NonCopyType = u16;
+impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
+    const TO_REMAIN_GENERIC: T = T::DEFAULT;
+    const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+}
 
-    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
-    const INTEGER: u64 = 10;
-    const STRING: String = String::new();
-    const SELF: Self = 11;
-    const INPUT: u32 = 12;
-    const ASSOC: Self::NonCopyType = 13;
+// a helper type used below
+struct Wrapper<T>(T);
+
+// a constant whose type is an associated type should be linted at the implementation site, too.
+trait AssocTypes {
+    type ToBeFrozen;
+    type ToBeUnfrozen;
+    type ToBeGenericParam;
+
+    const TO_BE_FROZEN: Self::ToBeFrozen;
+    const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
+    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
+    // to ensure it can handle things when a generic type remains after normalization.
+    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
 }
 
-struct Local<T, U>(T, U);
+impl<T: ConstDefault> AssocTypes for Vec<T> {
+    type ToBeFrozen = u16;
+    type ToBeUnfrozen = AtomicUsize;
+    type ToBeGenericParam = T;
+
+    const TO_BE_FROZEN: Self::ToBeFrozen = 12;
+    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
+}
+
+// a helper trait used below
+trait AssocTypesHelper {
+    type NotToBeBounded;
+    type ToBeBounded;
+
+    const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
+}
 
-impl<T: Trait2 + Trait<u32>, U: Trait2> Local<T, U> {
-    const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
+// a constant whose type is an assoc type originated from a generic param bounded at the definition
+// site should be linted at there.
+trait AssocTypesFromGenericParam<T>
+where
+    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+    const NOT_BOUNDED: T::NotToBeBounded;
+    const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+}
+
+impl<T> AssocTypesFromGenericParam<T> for u64
+where
+    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+    // an associated type could remain unknown in a trait impl.
+    const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+    const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
+}
+
+// a constant whose type is `Self` should be linted at the implementation site as well.
+// (`Option` requires `Sized` bound.)
+trait SelfType: Sized {
+    const SELF: Self;
+    // this was the one in the original issue (#5050).
+    const WRAPPED_SELF: Option<Self>;
+}
+
+impl SelfType for u64 {
+    const SELF: Self = 16;
+    const WRAPPED_SELF: Option<Self> = Some(20);
+}
+
+impl SelfType for AtomicUsize {
+    // this (interior mutable `Self` const) exists in `parking_lot`.
+    // `const_trait_impl` will replace it in the future, hopefully.
+    const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+}
+
+// Even though a constant contains a generic type, if it also have a interior mutable type,
+// it should be linted at the definition site.
+trait BothOfCellAndGeneric<T> {
+    // this is a false negative in the current implementation.
+    const DIRECT: Cell<T>;
+    const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+}
+
+impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
+    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
+    const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
+}
+
+struct Local<T>(T);
+
+// a constant in an inherent impl are essentially the same as a normal const item
+// except there can be a generic or associated type.
+impl<T> Local<T>
+where
+    T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
+{
+    const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
     const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-    const T_SELF: T = T::SELF_2;
-    const U_SELF: U = U::SELF_2;
-    //~^ ERROR interior mutable
-    //~| HELP consider requiring `U` to be `Copy`
-    const T_ASSOC: T::NonCopyType = T::ASSOC;
-    //~^ ERROR interior mutable
-    //~| HELP consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
-    const U_ASSOC: U::CopyType = U::ASSOC_2;
+
+    const GENERIC_TYPE: T = T::DEFAULT;
+
+    const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
+    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
 }
 
 fn main() {}
diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr
index 6a9a57361f9..5cb10be88d8 100644
--- a/tests/ui/declare_interior_mutable_const.stderr
+++ b/tests/ui/declare_interior_mutable_const.stderr
@@ -36,75 +36,75 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:40:5
+  --> $DIR/declare_interior_mutable_const.rs:39:5
    |
 LL |     const ATOMIC: AtomicUsize; //~ ERROR interior mutable
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:44:5
+  --> $DIR/declare_interior_mutable_const.rs:16:9
+   |
+LL |         const $name: $ty = $e;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable
+   |     ----------------------------------------------------------- in this macro invocation
    |
-LL |     const INPUT: T;
-   |     ^^^^^^^^^^^^^-^
-   |                  |
-   |                  consider requiring `T` to be `Copy`
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:47:5
+  --> $DIR/declare_interior_mutable_const.rs:67:5
    |
-LL |     const ASSOC: Self::NonCopyType;
-   |     ^^^^^^^^^^^^^-----------------^
-   |                  |
-   |                  consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
+LL |     const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:51:5
+  --> $DIR/declare_interior_mutable_const.rs:92:5
    |
-LL |     const AN_INPUT: T = Self::INPUT;
-   |     ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^
-   |                     |
-   |                     consider requiring `T` to be `Copy`
+LL |     const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:16:9
+  --> $DIR/declare_interior_mutable_const.rs:93:5
    |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
-   |     ----------------------------------------------- in this macro invocation
+LL |     const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:112:5
    |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |     const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should never be interior mutable
+  --> $DIR/declare_interior_mutable_const.rs:140:5
+   |
+LL |     const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:60:5
+  --> $DIR/declare_interior_mutable_const.rs:141:5
    |
-LL |     const SELF_2: Self;
-   |     ^^^^^^^^^^^^^^----^
-   |                   |
-   |                   consider requiring `Self` to be `Copy`
+LL |     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:81:5
+  --> $DIR/declare_interior_mutable_const.rs:149:5
    |
-LL |     const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:84:5
+  --> $DIR/declare_interior_mutable_const.rs:165:5
    |
-LL |     const U_SELF: U = U::SELF_2;
-   |     ^^^^^^^^^^^^^^-^^^^^^^^^^^^^
-   |                   |
-   |                   consider requiring `U` to be `Copy`
+LL |     const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should never be interior mutable
-  --> $DIR/declare_interior_mutable_const.rs:87:5
+  --> $DIR/declare_interior_mutable_const.rs:171:5
    |
-LL |     const T_ASSOC: T::NonCopyType = T::ASSOC;
-   |     ^^^^^^^^^^^^^^^--------------^^^^^^^^^^^^
-   |                    |
-   |                    consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
+LL |     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs
index 9181d789d4f..6b5bcdaa78e 100644
--- a/tests/ui/drop_ref.rs
+++ b/tests/ui/drop_ref.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::drop_ref)]
 #![allow(clippy::toplevel_ref_arg)]
+#![allow(clippy::map_err_ignore)]
 
 use std::mem::drop;
 
diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr
index 35ae88b78a4..7974bf56d44 100644
--- a/tests/ui/drop_ref.stderr
+++ b/tests/ui/drop_ref.stderr
@@ -1,108 +1,108 @@
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:9:5
+  --> $DIR/drop_ref.rs:10:5
    |
 LL |     drop(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::drop-ref` implied by `-D warnings`
 note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:9:10
+  --> $DIR/drop_ref.rs:10:10
    |
 LL |     drop(&SomeStruct);
    |          ^^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:12:5
+  --> $DIR/drop_ref.rs:13:5
    |
 LL |     drop(&owned1);
    |     ^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:12:10
+  --> $DIR/drop_ref.rs:13:10
    |
 LL |     drop(&owned1);
    |          ^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:13:5
+  --> $DIR/drop_ref.rs:14:5
    |
 LL |     drop(&&owned1);
    |     ^^^^^^^^^^^^^^
    |
 note: argument has type `&&SomeStruct`
-  --> $DIR/drop_ref.rs:13:10
+  --> $DIR/drop_ref.rs:14:10
    |
 LL |     drop(&&owned1);
    |          ^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:14:5
+  --> $DIR/drop_ref.rs:15:5
    |
 LL |     drop(&mut owned1);
    |     ^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&mut SomeStruct`
-  --> $DIR/drop_ref.rs:14:10
+  --> $DIR/drop_ref.rs:15:10
    |
 LL |     drop(&mut owned1);
    |          ^^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:18:5
+  --> $DIR/drop_ref.rs:19:5
    |
 LL |     drop(reference1);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:18:10
+  --> $DIR/drop_ref.rs:19:10
    |
 LL |     drop(reference1);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:21:5
+  --> $DIR/drop_ref.rs:22:5
    |
 LL |     drop(reference2);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type `&mut SomeStruct`
-  --> $DIR/drop_ref.rs:21:10
+  --> $DIR/drop_ref.rs:22:10
    |
 LL |     drop(reference2);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:24:5
+  --> $DIR/drop_ref.rs:25:5
    |
 LL |     drop(reference3);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:24:10
+  --> $DIR/drop_ref.rs:25:10
    |
 LL |     drop(reference3);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:29:5
+  --> $DIR/drop_ref.rs:30:5
    |
 LL |     drop(&val);
    |     ^^^^^^^^^^
    |
 note: argument has type `&T`
-  --> $DIR/drop_ref.rs:29:10
+  --> $DIR/drop_ref.rs:30:10
    |
 LL |     drop(&val);
    |          ^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_ref.rs:37:5
+  --> $DIR/drop_ref.rs:38:5
    |
 LL |     std::mem::drop(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:37:20
+  --> $DIR/drop_ref.rs:38:20
    |
 LL |     std::mem::drop(&SomeStruct);
    |                    ^^^^^^^^^^^
diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs
index aa6ef162fe4..81d8221bd13 100644
--- a/tests/ui/explicit_counter_loop.rs
+++ b/tests/ui/explicit_counter_loop.rs
@@ -38,54 +38,54 @@ mod issue_1219 {
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 continue;
             }
             count += 1;
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 count += 1;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             if ch == 'a' {
                 continue;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 let _ = 123;
             }
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 count += 1;
             }
-            println!("{}", count);
         }
     }
 }
@@ -96,30 +96,30 @@ mod issue_3308 {
         let mut skips = 0;
         let erasures = vec![];
         for i in 0..10 {
+            println!("{}", skips);
             while erasures.contains(&(i + skips)) {
                 skips += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             let mut j = 0;
             while j < 5 {
                 skips += 1;
                 j += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             for j in 0..5 {
                 skips += 1;
             }
-            println!("{}", skips);
         }
     }
 }
@@ -145,3 +145,16 @@ mod issue_4732 {
         let _closure = || println!("index: {}", index);
     }
 }
+
+mod issue_4677 {
+    pub fn test() {
+        let slice = &[1, 2, 3];
+
+        // should not trigger the lint because the count is used after incremented
+        let mut count = 0;
+        for _i in slice {
+            count += 1;
+            println!("{}", count);
+        }
+    }
+}
diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr
index 2d454e8e70d..f7c380fc915 100644
--- a/tests/ui/float_cmp.stderr
+++ b/tests/ui/float_cmp.stderr
@@ -2,34 +2,34 @@ error: strict comparison of `f32` or `f64`
   --> $DIR/float_cmp.rs:65:5
    |
 LL |     ONE as f64 != 2.0;
-   |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() > error`
+   |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
    |
    = note: `-D clippy::float-cmp` implied by `-D warnings`
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
   --> $DIR/float_cmp.rs:70:5
    |
 LL |     x == 1.0;
-   |     ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error`
+   |     ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
   --> $DIR/float_cmp.rs:73:5
    |
 LL |     twice(x) != twice(ONE as f64);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() > error`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
   --> $DIR/float_cmp.rs:93:5
    |
 LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` arrays
   --> $DIR/float_cmp.rs:98:5
@@ -37,15 +37,15 @@ error: strict comparison of `f32` or `f64` arrays
 LL |     a1 == a2;
    |     ^^^^^^^^
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
   --> $DIR/float_cmp.rs:99:5
    |
 LL |     a1[0] == a2[0];
-   |     ^^^^^^^^^^^^^^ help: consider comparing them within some error: `(a1[0] - a2[0]).abs() < error`
+   |     ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr
index 19dc4a284b7..5d0455363e8 100644
--- a/tests/ui/float_cmp_const.stderr
+++ b/tests/ui/float_cmp_const.stderr
@@ -2,58 +2,58 @@ error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:20:5
    |
 LL |     1f32 == ONE;
-   |     ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error`
+   |     ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
    |
    = note: `-D clippy::float-cmp-const` implied by `-D warnings`
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:21:5
    |
 LL |     TWO == ONE;
-   |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
+   |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:22:5
    |
 LL |     TWO != ONE;
-   |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() > error`
+   |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:23:5
    |
 LL |     ONE + ONE == TWO;
-   |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error`
+   |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:25:5
    |
 LL |     x as f32 == ONE;
-   |     ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(x as f32 - ONE).abs() < error`
+   |     ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:28:5
    |
 LL |     v == ONE;
-   |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
+   |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
   --> $DIR/float_cmp_const.rs:29:5
    |
 LL |     v != ONE;
-   |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() > error`
+   |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant arrays
   --> $DIR/float_cmp_const.rs:61:5
@@ -61,7 +61,7 @@ error: strict comparison of `f32` or `f64` constant arrays
 LL |     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error`
+   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs
index 000d5269930..ca8ca53c80c 100644
--- a/tests/ui/indexing_slicing_index.rs
+++ b/tests/ui/indexing_slicing_index.rs
@@ -15,7 +15,8 @@ fn main() {
     x[3]; // Ok, should not produce stderr.
 
     let y = &x;
-    y[0];
+    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
+    y[4]; // Ok, rustc will handle references too.
 
     let v = vec![0; 5];
     v[0];
diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr
index 2b3f9be2dfb..2f6c9e2f4e5 100644
--- a/tests/ui/indexing_slicing_index.stderr
+++ b/tests/ui/indexing_slicing_index.stderr
@@ -8,15 +8,7 @@ LL |     x[index];
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:18:5
-   |
-LL |     y[0];
-   |     ^^^^
-   |
-   = help: Consider using `.get(n)` or `.get_mut(n)` instead
-
-error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:21:5
+  --> $DIR/indexing_slicing_index.rs:22:5
    |
 LL |     v[0];
    |     ^^^^
@@ -24,7 +16,7 @@ LL |     v[0];
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:22:5
+  --> $DIR/indexing_slicing_index.rs:23:5
    |
 LL |     v[10];
    |     ^^^^^
@@ -32,7 +24,7 @@ LL |     v[10];
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:23:5
+  --> $DIR/indexing_slicing_index.rs:24:5
    |
 LL |     v[1 << 3];
    |     ^^^^^^^^^
@@ -40,7 +32,7 @@ LL |     v[1 << 3];
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:29:5
+  --> $DIR/indexing_slicing_index.rs:30:5
    |
 LL |     v[N];
    |     ^^^^
@@ -48,12 +40,12 @@ LL |     v[N];
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic.
-  --> $DIR/indexing_slicing_index.rs:30:5
+  --> $DIR/indexing_slicing_index.rs:31:5
    |
 LL |     v[M];
    |     ^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/indexing_slicing_slice.stderr b/tests/ui/indexing_slicing_slice.stderr
index ec6c157ac1a..2231deee833 100644
--- a/tests/ui/indexing_slicing_slice.stderr
+++ b/tests/ui/indexing_slicing_slice.stderr
@@ -71,29 +71,17 @@ LL |     &x[1..][..5];
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
 
-error: slicing may panic.
-  --> $DIR/indexing_slicing_slice.rs:24:6
-   |
-LL |     &y[1..2];
-   |      ^^^^^^^
-   |
-   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
-
-error: slicing may panic.
-  --> $DIR/indexing_slicing_slice.rs:25:6
+error: range is out of bounds
+  --> $DIR/indexing_slicing_slice.rs:25:12
    |
 LL |     &y[0..=4];
-   |      ^^^^^^^^
-   |
-   = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
+   |            ^
 
-error: slicing may panic.
-  --> $DIR/indexing_slicing_slice.rs:26:6
+error: range is out of bounds
+  --> $DIR/indexing_slicing_slice.rs:26:11
    |
 LL |     &y[..=4];
-   |      ^^^^^^^
-   |
-   = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
+   |           ^
 
 error: slicing may panic.
   --> $DIR/indexing_slicing_slice.rs:31:6
@@ -133,5 +121,5 @@ LL |     &v[..100];
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr
index 1cd6400b019..28003b365bb 100644
--- a/tests/ui/into_iter_on_ref.stderr
+++ b/tests/ui/into_iter_on_ref.stderr
@@ -1,4 +1,4 @@
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
   --> $DIR/into_iter_on_ref.rs:14:30
    |
 LL |     let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
@@ -6,157 +6,157 @@ LL |     let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
    |
    = note: `-D clippy::into-iter-on-ref` implied by `-D warnings`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
   --> $DIR/into_iter_on_ref.rs:15:46
    |
 LL |     let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
    |                                              ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
   --> $DIR/into_iter_on_ref.rs:16:41
    |
 LL |     let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `slice`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
   --> $DIR/into_iter_on_ref.rs:17:44
    |
 LL |     let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
   --> $DIR/into_iter_on_ref.rs:19:32
    |
 LL |     let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
    |                                ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
   --> $DIR/into_iter_on_ref.rs:20:36
    |
 LL |     let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
    |                                    ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array`
   --> $DIR/into_iter_on_ref.rs:21:40
    |
 LL |     let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
    |                                        ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Option`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option`
   --> $DIR/into_iter_on_ref.rs:23:24
    |
 LL |     let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
    |                        ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Option`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option`
   --> $DIR/into_iter_on_ref.rs:24:28
    |
 LL |     let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
    |                            ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Result`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result`
   --> $DIR/into_iter_on_ref.rs:25:32
    |
 LL |     let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
    |                                ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Result`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result`
   --> $DIR/into_iter_on_ref.rs:26:37
    |
 LL |     let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                     ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
   --> $DIR/into_iter_on_ref.rs:27:34
    |
 LL |     let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                  ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `Vec`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec`
   --> $DIR/into_iter_on_ref.rs:28:38
    |
 LL |     let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                      ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeMap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap`
   --> $DIR/into_iter_on_ref.rs:29:44
    |
 LL |     let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `BTreeMap`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap`
   --> $DIR/into_iter_on_ref.rs:30:48
    |
 LL |     let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                                ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `VecDeque`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque`
   --> $DIR/into_iter_on_ref.rs:31:39
    |
 LL |     let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `VecDeque`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque`
   --> $DIR/into_iter_on_ref.rs:32:43
    |
 LL |     let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                           ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `LinkedList`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList`
   --> $DIR/into_iter_on_ref.rs:33:41
    |
 LL |     let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `LinkedList`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList`
   --> $DIR/into_iter_on_ref.rs:34:45
    |
 LL |     let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                             ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashMap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap`
   --> $DIR/into_iter_on_ref.rs:35:43
    |
 LL |     let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not move the `HashMap`
+error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap`
   --> $DIR/into_iter_on_ref.rs:36:47
    |
 LL |     let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
    |                                               ^^^^^^^^^ help: call directly: `iter_mut`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BTreeSet`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet`
   --> $DIR/into_iter_on_ref.rs:38:39
    |
 LL |     let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `BinaryHeap`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap`
   --> $DIR/into_iter_on_ref.rs:39:41
    |
 LL |     let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `HashSet`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet`
   --> $DIR/into_iter_on_ref.rs:40:38
    |
 LL |     let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
    |                                      ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `Path`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path`
   --> $DIR/into_iter_on_ref.rs:41:43
    |
 LL |     let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `PathBuf`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf`
   --> $DIR/into_iter_on_ref.rs:42:47
    |
 LL |     let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
    |                                               ^^^^^^^^^ help: call directly: `iter`
 
-error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
   --> $DIR/into_iter_on_ref.rs:44:26
    |
 LL |     let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter()
diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs
index 802beeb4be6..32a67f181df 100644
--- a/tests/ui/let_if_seq.rs
+++ b/tests/ui/let_if_seq.rs
@@ -33,6 +33,7 @@ fn issue985_alt() -> i32 {
     x
 }
 
+#[allow(clippy::manual_strip)]
 fn issue975() -> String {
     let mut udn = "dummy".to_string();
     if udn.starts_with("uuid:") {
diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr
index c53a63a541b..7de560c7348 100644
--- a/tests/ui/let_if_seq.stderr
+++ b/tests/ui/let_if_seq.stderr
@@ -1,5 +1,5 @@
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:63:5
+  --> $DIR/let_if_seq.rs:64:5
    |
 LL | /     let mut foo = 0;
 LL | |     if f() {
@@ -11,7 +11,7 @@ LL | |     }
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:68:5
+  --> $DIR/let_if_seq.rs:69:5
    |
 LL | /     let mut bar = 0;
 LL | |     if f() {
@@ -25,7 +25,7 @@ LL | |     }
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:76:5
+  --> $DIR/let_if_seq.rs:77:5
    |
 LL | /     let quz;
 LL | |     if f() {
@@ -36,7 +36,7 @@ LL | |     }
    | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:105:5
+  --> $DIR/let_if_seq.rs:106:5
    |
 LL | /     let mut baz = 0;
 LL | |     if f() {
diff --git a/tests/ui/manual_strip.rs b/tests/ui/manual_strip.rs
new file mode 100644
index 00000000000..cbb84eb5c7e
--- /dev/null
+++ b/tests/ui/manual_strip.rs
@@ -0,0 +1,66 @@
+#![warn(clippy::manual_strip)]
+
+fn main() {
+    let s = "abc";
+
+    if s.starts_with("ab") {
+        str::to_string(&s["ab".len()..]);
+        s["ab".len()..].to_string();
+
+        str::to_string(&s[2..]);
+        s[2..].to_string();
+    }
+
+    if s.ends_with("bc") {
+        str::to_string(&s[..s.len() - "bc".len()]);
+        s[..s.len() - "bc".len()].to_string();
+
+        str::to_string(&s[..s.len() - 2]);
+        s[..s.len() - 2].to_string();
+    }
+
+    // Character patterns
+    if s.starts_with('a') {
+        str::to_string(&s[1..]);
+        s[1..].to_string();
+    }
+
+    // Variable prefix
+    let prefix = "ab";
+    if s.starts_with(prefix) {
+        str::to_string(&s[prefix.len()..]);
+    }
+
+    // Constant prefix
+    const PREFIX: &str = "ab";
+    if s.starts_with(PREFIX) {
+        str::to_string(&s[PREFIX.len()..]);
+        str::to_string(&s[2..]);
+    }
+
+    // Constant target
+    const TARGET: &str = "abc";
+    if TARGET.starts_with(prefix) {
+        str::to_string(&TARGET[prefix.len()..]);
+    }
+
+    // String target - not mutated.
+    let s1: String = "abc".into();
+    if s1.starts_with("ab") {
+        s1[2..].to_uppercase();
+    }
+
+    // String target - mutated. (Don't lint.)
+    let mut s2: String = "abc".into();
+    if s2.starts_with("ab") {
+        s2.push('d');
+        s2[2..].to_uppercase();
+    }
+
+    // Target not stripped. (Don't lint.)
+    let s3 = String::from("abcd");
+    let s4 = String::from("efgh");
+    if s3.starts_with("ab") {
+        s4[2..].to_string();
+    }
+}
diff --git a/tests/ui/manual_strip.stderr b/tests/ui/manual_strip.stderr
new file mode 100644
index 00000000000..1352a8713d4
--- /dev/null
+++ b/tests/ui/manual_strip.stderr
@@ -0,0 +1,132 @@
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:7:24
+   |
+LL |         str::to_string(&s["ab".len()..]);
+   |                        ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-strip` implied by `-D warnings`
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:6:5
+   |
+LL |     if s.starts_with("ab") {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = s.strip_prefix("ab") {
+LL |         str::to_string(<stripped>);
+LL |         <stripped>.to_string();
+LL | 
+LL |         str::to_string(<stripped>);
+LL |         <stripped>.to_string();
+   |
+
+error: stripping a suffix manually
+  --> $DIR/manual_strip.rs:15:24
+   |
+LL |         str::to_string(&s[..s.len() - "bc".len()]);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the suffix was tested here
+  --> $DIR/manual_strip.rs:14:5
+   |
+LL |     if s.ends_with("bc") {
+   |     ^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_suffix` method
+   |
+LL |     if let Some(<stripped>) = s.strip_suffix("bc") {
+LL |         str::to_string(<stripped>);
+LL |         <stripped>.to_string();
+LL | 
+LL |         str::to_string(<stripped>);
+LL |         <stripped>.to_string();
+   |
+
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:24:24
+   |
+LL |         str::to_string(&s[1..]);
+   |                        ^^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:23:5
+   |
+LL |     if s.starts_with('a') {
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = s.strip_prefix('a') {
+LL |         str::to_string(<stripped>);
+LL |         <stripped>.to_string();
+   |
+
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:31:24
+   |
+LL |         str::to_string(&s[prefix.len()..]);
+   |                        ^^^^^^^^^^^^^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:30:5
+   |
+LL |     if s.starts_with(prefix) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = s.strip_prefix(prefix) {
+LL |         str::to_string(<stripped>);
+   |
+
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:37:24
+   |
+LL |         str::to_string(&s[PREFIX.len()..]);
+   |                        ^^^^^^^^^^^^^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:36:5
+   |
+LL |     if s.starts_with(PREFIX) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = s.strip_prefix(PREFIX) {
+LL |         str::to_string(<stripped>);
+LL |         str::to_string(<stripped>);
+   |
+
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:44:24
+   |
+LL |         str::to_string(&TARGET[prefix.len()..]);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:43:5
+   |
+LL |     if TARGET.starts_with(prefix) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = TARGET.strip_prefix(prefix) {
+LL |         str::to_string(<stripped>);
+   |
+
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:50:9
+   |
+LL |         s1[2..].to_uppercase();
+   |         ^^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:49:5
+   |
+LL |     if s1.starts_with("ab") {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL |     if let Some(<stripped>) = s1.strip_prefix("ab") {
+LL |         <stripped>.to_uppercase();
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs
new file mode 100644
index 00000000000..617b6422872
--- /dev/null
+++ b/tests/ui/map_err.rs
@@ -0,0 +1,25 @@
+#![warn(clippy::map_err_ignore)]
+use std::convert::TryFrom;
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
+enum Errors {
+    Ignored,
+}
+
+impl Error for Errors {}
+
+impl fmt::Display for Errors {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Error")
+    }
+}
+
+fn main() -> Result<(), Errors> {
+    let x = u32::try_from(-123_i32);
+
+    println!("{:?}", x.map_err(|_| Errors::Ignored));
+
+    Ok(())
+}
diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr
new file mode 100644
index 00000000000..7273f460380
--- /dev/null
+++ b/tests/ui/map_err.stderr
@@ -0,0 +1,11 @@
+error: `map_err(|_|...` ignores the original error
+  --> $DIR/map_err.rs:22:32
+   |
+LL |     println!("{:?}", x.map_err(|_| Errors::Ignored));
+   |                                ^^^
+   |
+   = note: `-D clippy::map-err-ignore` implied by `-D warnings`
+   = help: Consider wrapping the error in an enum variant
+
+error: aborting due to previous error
+
diff --git a/tests/ui/match_type_on_diag_item.rs b/tests/ui/match_type_on_diag_item.rs
new file mode 100644
index 00000000000..fe950b0aa7c
--- /dev/null
+++ b/tests/ui/match_type_on_diag_item.rs
@@ -0,0 +1,50 @@
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+
+mod paths {
+    pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
+}
+
+mod utils {
+    use super::*;
+
+    pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool {
+        false
+    }
+}
+
+use utils::match_type;
+
+declare_lint! {
+    pub TEST_LINT,
+    Warn,
+    ""
+}
+
+declare_lint_pass!(Pass => [TEST_LINT]);
+
+static OPTION: [&str; 3] = ["core", "option", "Option"];
+
+impl<'tcx> LateLintPass<'tcx> for Pass {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) {
+        let ty = cx.typeck_results().expr_ty(expr);
+
+        let _ = match_type(cx, ty, &paths::VEC);
+        let _ = match_type(cx, ty, &OPTION);
+        let _ = match_type(cx, ty, &["core", "result", "Result"]);
+
+        let rc_path = &["alloc", "rc", "Rc"];
+        let _ = utils::match_type(cx, ty, rc_path);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui/match_type_on_diag_item.stderr
new file mode 100644
index 00000000000..5e5fe9e3a3e
--- /dev/null
+++ b/tests/ui/match_type_on_diag_item.stderr
@@ -0,0 +1,33 @@
+error: usage of `utils::match_type()` on a type diagnostic item
+  --> $DIR/match_type_on_diag_item.rs:41:17
+   |
+LL |         let _ = match_type(cx, ty, &paths::VEC);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))`
+   |
+note: the lint level is defined here
+  --> $DIR/match_type_on_diag_item.rs:1:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+  --> $DIR/match_type_on_diag_item.rs:42:17
+   |
+LL |         let _ = match_type(cx, ty, &OPTION);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+  --> $DIR/match_type_on_diag_item.rs:43:17
+   |
+LL |         let _ = match_type(cx, ty, &["core", "result", "Result"]);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))`
+
+error: usage of `utils::match_type()` on a type diagnostic item
+  --> $DIR/match_type_on_diag_item.rs:46:17
+   |
+LL |         let _ = utils::match_type(cx, ty, rc_path);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(Rc))`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.rs b/tests/ui/needless_arbitrary_self_type_unfixable.rs
new file mode 100644
index 00000000000..a39d96109f1
--- /dev/null
+++ b/tests/ui/needless_arbitrary_self_type_unfixable.rs
@@ -0,0 +1,45 @@
+// aux-build:proc_macro_attr.rs
+
+#![warn(clippy::needless_arbitrary_self_type)]
+
+#[macro_use]
+extern crate proc_macro_attr;
+
+mod issue_6089 {
+    // Check that we don't lint if the `self` parameter comes from expansion
+
+    macro_rules! test_from_expansion {
+        () => {
+            trait T1 {
+                fn test(self: &Self);
+            }
+
+            struct S1 {}
+
+            impl T1 for S1 {
+                fn test(self: &Self) {}
+            }
+        };
+    }
+
+    test_from_expansion!();
+
+    // If only the lifetime name comes from expansion we will lint, but the suggestion will have
+    // placeholders and will not be applied automatically, as we can't reliably know the original name.
+    // This specific case happened with async_trait.
+
+    trait T2 {
+        fn call_with_mut_self(&mut self);
+    }
+
+    struct S2 {}
+
+    // The method's signature will be expanded to:
+    //  fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
+    #[rename_my_lifetimes]
+    impl T2 for S2 {
+        fn call_with_mut_self(self: &mut Self) {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/tests/ui/needless_arbitrary_self_type_unfixable.stderr
new file mode 100644
index 00000000000..44a0e6ddeac
--- /dev/null
+++ b/tests/ui/needless_arbitrary_self_type_unfixable.stderr
@@ -0,0 +1,10 @@
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+   |
+LL |         fn call_with_mut_self(self: &mut Self) {}
+   |                               ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
+   |
+   = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index 695a460cc4e..a7fb00a2705 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
+#![allow(clippy::redundant_closure)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     string.map_or((false, "hello"), |x| (true, x))
@@ -36,6 +37,14 @@ fn longer_body(arg: Option<u32>) -> u32 {
     })
 }
 
+fn impure_else(arg: Option<i32>) {
+    let side_effect = || {
+        println!("return 1");
+        1
+    };
+    let _ = arg.map_or_else(|| side_effect(), |x| x);
+}
+
 fn test_map_or_else(arg: Option<u32>) {
     let _ = arg.map_or_else(|| {
         let mut y = 1;
@@ -71,4 +80,5 @@ fn main() {
     let _ = longer_body(None);
     test_map_or_else(None);
     let _ = negative_tests(None);
+    let _ = impure_else(None);
 }
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index dee80d26bd9..895fd86321f 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
+#![allow(clippy::redundant_closure)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     if let Some(x) = string {
@@ -52,6 +53,19 @@ fn longer_body(arg: Option<u32>) -> u32 {
     }
 }
 
+fn impure_else(arg: Option<i32>) {
+    let side_effect = || {
+        println!("return 1");
+        1
+    };
+    let _ = if let Some(x) = arg {
+        x
+    } else {
+        // map_or_else must be suggested
+        side_effect()
+    };
+}
+
 fn test_map_or_else(arg: Option<u32>) {
     let _ = if let Some(x) = arg {
         x * x * x * x
@@ -89,4 +103,5 @@ fn main() {
     let _ = longer_body(None);
     test_map_or_else(None);
     let _ = negative_tests(None);
+    let _ = impure_else(None);
 }
diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr
index 7005850efaf..b69fe767682 100644
--- a/tests/ui/option_if_let_else.stderr
+++ b/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:5:5
+  --> $DIR/option_if_let_else.rs:6:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,7 +11,7 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:15:12
+  --> $DIR/option_if_let_else.rs:16:12
    |
 LL |       } else if let Some(x) = string {
    |  ____________^
@@ -22,19 +22,19 @@ LL | |     }
    | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:23:13
+  --> $DIR/option_if_let_else.rs:24:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:24:13
+  --> $DIR/option_if_let_else.rs:25:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:25:13
+  --> $DIR/option_if_let_else.rs:26:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -54,13 +54,13 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -80,7 +80,7 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -100,7 +100,7 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:47:5
+  --> $DIR/option_if_let_else.rs:48:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -119,7 +119,19 @@ LL |     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:56:13
+  --> $DIR/option_if_let_else.rs:61:13
+   |
+LL |       let _ = if let Some(x) = arg {
+   |  _____________^
+LL | |         x
+LL | |     } else {
+LL | |         // map_or_else must be suggested
+LL | |         side_effect()
+LL | |     };
+   | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
+
+error: use Option::map_or_else instead of an if let/else
+  --> $DIR/option_if_let_else.rs:70:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -142,10 +154,10 @@ LL |     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:85:13
+  --> $DIR/option_if_let_else.rs:99:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr
index 1312c70b6d5..d7d45ef9b0b 100644
--- a/tests/ui/option_map_unit_fn_fixable.stderr
+++ b/tests/ui/option_map_unit_fn_fixable.stderr
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:38:5
    |
 LL |     x.field.map(do_nothing);
@@ -8,7 +8,7 @@ LL |     x.field.map(do_nothing);
    |
    = note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:40:5
    |
 LL |     x.field.map(do_nothing);
@@ -16,7 +16,7 @@ LL |     x.field.map(do_nothing);
    |     |
    |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:42:5
    |
 LL |     x.field.map(diverge);
@@ -24,7 +24,7 @@ LL |     x.field.map(diverge);
    |     |
    |     help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:48:5
    |
 LL |     x.field.map(|value| x.do_option_nothing(value + captured));
@@ -32,7 +32,7 @@ LL |     x.field.map(|value| x.do_option_nothing(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:50:5
    |
 LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
@@ -40,7 +40,7 @@ LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:53:5
    |
 LL |     x.field.map(|value| do_nothing(value + captured));
@@ -48,7 +48,7 @@ LL |     x.field.map(|value| do_nothing(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:55:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured) });
@@ -56,7 +56,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:57:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured); });
@@ -64,7 +64,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:59:5
    |
 LL |     x.field.map(|value| { { do_nothing(value + captured); } });
@@ -72,7 +72,7 @@ LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:62:5
    |
 LL |     x.field.map(|value| diverge(value + captured));
@@ -80,7 +80,7 @@ LL |     x.field.map(|value| diverge(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:64:5
    |
 LL |     x.field.map(|value| { diverge(value + captured) });
@@ -88,7 +88,7 @@ LL |     x.field.map(|value| { diverge(value + captured) });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:66:5
    |
 LL |     x.field.map(|value| { diverge(value + captured); });
@@ -96,7 +96,7 @@ LL |     x.field.map(|value| { diverge(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:68:5
    |
 LL |     x.field.map(|value| { { diverge(value + captured); } });
@@ -104,7 +104,7 @@ LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:73:5
    |
 LL |     x.field.map(|value| { let y = plus_one(value + captured); });
@@ -112,7 +112,7 @@ LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:75:5
    |
 LL |     x.field.map(|value| { plus_one(value + captured); });
@@ -120,7 +120,7 @@ LL |     x.field.map(|value| { plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:77:5
    |
 LL |     x.field.map(|value| { { plus_one(value + captured); } });
@@ -128,7 +128,7 @@ LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:80:5
    |
 LL |     x.field.map(|ref value| { do_nothing(value + captured) });
@@ -136,7 +136,7 @@ LL |     x.field.map(|ref value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:82:5
    |
 LL |     option().map(do_nothing);}
diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed
index 5fb568672d3..2045ffdb5f0 100644
--- a/tests/ui/or_fun_call.fixed
+++ b/tests/ui/or_fun_call.fixed
@@ -58,6 +58,12 @@ fn or_fun_call() {
     let without_default = Some(Foo);
     without_default.unwrap_or_else(Foo::new);
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert_with(String::new);
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert_with(String::new);
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or_else(|| "".to_owned());
 
@@ -110,23 +116,4 @@ fn f() -> Option<()> {
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs
index 737b0f7e55b..522f31b72d0 100644
--- a/tests/ui/or_fun_call.rs
+++ b/tests/ui/or_fun_call.rs
@@ -58,6 +58,12 @@ fn or_fun_call() {
     let without_default = Some(Foo);
     without_default.unwrap_or(Foo::new());
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or("".to_owned());
 
@@ -110,23 +116,4 @@ fn f() -> Option<()> {
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
index b8a436993f3..bc5978b538f 100644
--- a/tests/ui/or_fun_call.stderr
+++ b/tests/ui/or_fun_call.stderr
@@ -60,23 +60,35 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:62:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:65:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
 error: use of `unwrap_or` followed by a function call
-  --> $DIR/or_fun_call.rs:62:21
+  --> $DIR/or_fun_call.rs:68:21
    |
 LL |     let _ = stringy.unwrap_or("".to_owned());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:87:35
+  --> $DIR/or_fun_call.rs:93:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:91:10
+  --> $DIR/or_fun_call.rs:97:10
    |
 LL |         .or(Some(Bar(b, Duration::from_secs(2))));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs
new file mode 100644
index 00000000000..287726f7a2d
--- /dev/null
+++ b/tests/ui/panic_in_result_fn.rs
@@ -0,0 +1,70 @@
+#![warn(clippy::panic_in_result_fn)]
+
+struct A;
+
+impl A {
+    fn result_with_panic() -> Result<bool, String> // should emit lint
+    {
+        panic!("error");
+    }
+
+    fn result_with_unimplemented() -> Result<bool, String> // should emit lint
+    {
+        unimplemented!();
+    }
+
+    fn result_with_unreachable() -> Result<bool, String> // should emit lint
+    {
+        unreachable!();
+    }
+
+    fn result_with_todo() -> Result<bool, String> // should emit lint
+    {
+        todo!("Finish this");
+    }
+
+    fn other_with_panic() // should not emit lint
+    {
+        panic!("");
+    }
+
+    fn other_with_unreachable() // should not emit lint
+    {
+        unreachable!();
+    }
+
+    fn other_with_unimplemented() // should not emit lint
+    {
+        unimplemented!();
+    }
+
+    fn other_with_todo() // should not emit lint
+    {
+        todo!("finish this")
+    }
+
+    fn result_without_banned_functions() -> Result<bool, String> // should not emit lint
+    {
+        Ok(true)
+    }
+}
+
+fn function_result_with_panic() -> Result<bool, String> // should emit lint
+{
+    panic!("error");
+}
+
+fn todo() {
+    println!("something");
+}
+
+fn function_result_with_custom_todo() -> Result<bool, String> // should not emit lint
+{
+    todo();
+    Ok(true)
+}
+
+fn main() -> Result<(), String> {
+    todo!("finish main method");
+    Ok(())
+}
diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr
new file mode 100644
index 00000000000..c6936fd8692
--- /dev/null
+++ b/tests/ui/panic_in_result_fn.stderr
@@ -0,0 +1,105 @@
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:6:5
+   |
+LL | /     fn result_with_panic() -> Result<bool, String> // should emit lint
+LL | |     {
+LL | |         panic!("error");
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:8:9
+   |
+LL |         panic!("error");
+   |         ^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:11:5
+   |
+LL | /     fn result_with_unimplemented() -> Result<bool, String> // should emit lint
+LL | |     {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+   |
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:13:9
+   |
+LL |         unimplemented!();
+   |         ^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:16:5
+   |
+LL | /     fn result_with_unreachable() -> Result<bool, String> // should emit lint
+LL | |     {
+LL | |         unreachable!();
+LL | |     }
+   | |_____^
+   |
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:18:9
+   |
+LL |         unreachable!();
+   |         ^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:21:5
+   |
+LL | /     fn result_with_todo() -> Result<bool, String> // should emit lint
+LL | |     {
+LL | |         todo!("Finish this");
+LL | |     }
+   | |_____^
+   |
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:23:9
+   |
+LL |         todo!("Finish this");
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:52:1
+   |
+LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
+LL | | {
+LL | |     panic!("error");
+LL | | }
+   | |_^
+   |
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:54:5
+   |
+LL |     panic!("error");
+   |     ^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result`
+  --> $DIR/panic_in_result_fn.rs:67:1
+   |
+LL | / fn main() -> Result<(), String> {
+LL | |     todo!("finish main method");
+LL | |     Ok(())
+LL | | }
+   | |_^
+   |
+   = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+note: return Err() instead of panicking
+  --> $DIR/panic_in_result_fn.rs:68:5
+   |
+LL |     todo!("finish main method");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/print_stdout_build_script.rs b/tests/ui/print_stdout_build_script.rs
new file mode 100644
index 00000000000..997ebef8a69
--- /dev/null
+++ b/tests/ui/print_stdout_build_script.rs
@@ -0,0 +1,12 @@
+// compile-flags: --crate-name=build_script_build
+
+#![warn(clippy::print_stdout)]
+
+fn main() {
+    // Fix #6041
+    //
+    // The `print_stdout` lint shouldn't emit in `build.rs`
+    // as these methods are used for the build script.
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs
index 3f710540e90..a43a1fc4f52 100644
--- a/tests/ui/print_with_newline.rs
+++ b/tests/ui/print_with_newline.rs
@@ -9,6 +9,7 @@ fn main() {
     print!("Hello {}\n", "world");
     print!("Hello {} {}\n", "world", "#2");
     print!("{}\n", 1265);
+    print!("\n");
 
     // these are all fine
     print!("");
diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr
index 05fe88915d6..54b3ad75b31 100644
--- a/tests/ui/print_with_newline.stderr
+++ b/tests/ui/print_with_newline.stderr
@@ -44,7 +44,18 @@ LL |     println!("{}", 1265);
    |     ^^^^^^^    --
 
 error: using `print!()` with a format string that ends in a single newline
-  --> $DIR/print_with_newline.rs:30:5
+  --> $DIR/print_with_newline.rs:12:5
+   |
+LL |     print!("/n");
+   |     ^^^^^^^^^^^^
+   |
+help: use `println!` instead
+   |
+LL |     println!();
+   |     ^^^^^^^ --
+
+error: using `print!()` with a format string that ends in a single newline
+  --> $DIR/print_with_newline.rs:31:5
    |
 LL |     print!("//n"); // should fail
    |     ^^^^^^^^^^^^^^
@@ -55,7 +66,7 @@ LL |     println!("/"); // should fail
    |     ^^^^^^^    --
 
 error: using `print!()` with a format string that ends in a single newline
-  --> $DIR/print_with_newline.rs:37:5
+  --> $DIR/print_with_newline.rs:38:5
    |
 LL | /     print!(
 LL | |         "
@@ -70,7 +81,7 @@ LL |         ""
    |
 
 error: using `print!()` with a format string that ends in a single newline
-  --> $DIR/print_with_newline.rs:41:5
+  --> $DIR/print_with_newline.rs:42:5
    |
 LL | /     print!(
 LL | |         r"
@@ -85,7 +96,7 @@ LL |         r""
    |
 
 error: using `print!()` with a format string that ends in a single newline
-  --> $DIR/print_with_newline.rs:49:5
+  --> $DIR/print_with_newline.rs:50:5
    |
 LL |     print!("/r/n"); //~ ERROR
    |     ^^^^^^^^^^^^^^^
@@ -96,7 +107,7 @@ LL |     println!("/r"); //~ ERROR
    |     ^^^^^^^     --
 
 error: using `print!()` with a format string that ends in a single newline
-  --> $DIR/print_with_newline.rs:50:5
+  --> $DIR/print_with_newline.rs:51:5
    |
 LL |     print!("foo/rbar/n") // ~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -106,5 +117,5 @@ help: use `println!` instead
 LL |     println!("foo/rbar") // ~ ERROR
    |     ^^^^^^^          --
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs
new file mode 100644
index 00000000000..1fa98643936
--- /dev/null
+++ b/tests/ui/rc_buffer.rs
@@ -0,0 +1,26 @@
+#![warn(clippy::rc_buffer)]
+
+use std::cell::RefCell;
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+struct S {
+    // triggers lint
+    bad1: Rc<String>,
+    bad2: Rc<PathBuf>,
+    bad3: Rc<Vec<u8>>,
+    bad4: Rc<OsString>,
+    // does not trigger lint
+    good1: Rc<RefCell<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Rc<String>) {}
+fn func_bad2(_: Rc<PathBuf>) {}
+fn func_bad3(_: Rc<Vec<u8>>) {}
+fn func_bad4(_: Rc<OsString>) {}
+// does not trigger lint
+fn func_good1(_: Rc<RefCell<String>>) {}
+
+fn main() {}
diff --git a/tests/ui/rc_buffer.stderr b/tests/ui/rc_buffer.stderr
new file mode 100644
index 00000000000..e4cc169af07
--- /dev/null
+++ b/tests/ui/rc_buffer.stderr
@@ -0,0 +1,52 @@
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:10:11
+   |
+LL |     bad1: Rc<String>,
+   |           ^^^^^^^^^^ help: try: `Rc<str>`
+   |
+   = note: `-D clippy::rc-buffer` implied by `-D warnings`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:11:11
+   |
+LL |     bad2: Rc<PathBuf>,
+   |           ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:12:11
+   |
+LL |     bad3: Rc<Vec<u8>>,
+   |           ^^^^^^^^^^^ help: try: `Rc<[u8]>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:13:11
+   |
+LL |     bad4: Rc<OsString>,
+   |           ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:19:17
+   |
+LL | fn func_bad1(_: Rc<String>) {}
+   |                 ^^^^^^^^^^ help: try: `Rc<str>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:20:17
+   |
+LL | fn func_bad2(_: Rc<PathBuf>) {}
+   |                 ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:21:17
+   |
+LL | fn func_bad3(_: Rc<Vec<u8>>) {}
+   |                 ^^^^^^^^^^^ help: try: `Rc<[u8]>`
+
+error: usage of `Rc<T>` when T is a buffer type
+  --> $DIR/rc_buffer.rs:22:17
+   |
+LL | fn func_bad4(_: Rc<OsString>) {}
+   |                 ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs
new file mode 100644
index 00000000000..5d586584817
--- /dev/null
+++ b/tests/ui/rc_buffer_arc.rs
@@ -0,0 +1,25 @@
+#![warn(clippy::rc_buffer)]
+
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::sync::{Arc, Mutex};
+
+struct S {
+    // triggers lint
+    bad1: Arc<String>,
+    bad2: Arc<PathBuf>,
+    bad3: Arc<Vec<u8>>,
+    bad4: Arc<OsString>,
+    // does not trigger lint
+    good1: Arc<Mutex<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Arc<String>) {}
+fn func_bad2(_: Arc<PathBuf>) {}
+fn func_bad3(_: Arc<Vec<u8>>) {}
+fn func_bad4(_: Arc<OsString>) {}
+// does not trigger lint
+fn func_good1(_: Arc<Mutex<String>>) {}
+
+fn main() {}
diff --git a/tests/ui/rc_buffer_arc.stderr b/tests/ui/rc_buffer_arc.stderr
new file mode 100644
index 00000000000..8252270d2ac
--- /dev/null
+++ b/tests/ui/rc_buffer_arc.stderr
@@ -0,0 +1,52 @@
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:9:11
+   |
+LL |     bad1: Arc<String>,
+   |           ^^^^^^^^^^^ help: try: `Arc<str>`
+   |
+   = note: `-D clippy::rc-buffer` implied by `-D warnings`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:10:11
+   |
+LL |     bad2: Arc<PathBuf>,
+   |           ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:11:11
+   |
+LL |     bad3: Arc<Vec<u8>>,
+   |           ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:12:11
+   |
+LL |     bad4: Arc<OsString>,
+   |           ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:18:17
+   |
+LL | fn func_bad1(_: Arc<String>) {}
+   |                 ^^^^^^^^^^^ help: try: `Arc<str>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:19:17
+   |
+LL | fn func_bad2(_: Arc<PathBuf>) {}
+   |                 ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:20:17
+   |
+LL | fn func_bad3(_: Arc<Vec<u8>>) {}
+   |                 ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
+
+error: usage of `Arc<T>` when T is a buffer type
+  --> $DIR/rc_buffer_arc.rs:21:17
+   |
+LL | fn func_bad4(_: Arc<OsString>) {}
+   |                 ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/rc_buffer_redefined_string.rs b/tests/ui/rc_buffer_redefined_string.rs
new file mode 100644
index 00000000000..5d31a848cf7
--- /dev/null
+++ b/tests/ui/rc_buffer_redefined_string.rs
@@ -0,0 +1,12 @@
+#![warn(clippy::rc_buffer)]
+
+use std::rc::Rc;
+
+struct String;
+
+struct S {
+    // does not trigger lint
+    good1: Rc<String>,
+}
+
+fn main() {}
diff --git a/tests/ui/rc_buffer_redefined_string.stderr b/tests/ui/rc_buffer_redefined_string.stderr
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tests/ui/rc_buffer_redefined_string.stderr
diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed
index adbff8af8d9..fe8f62503b7 100644
--- a/tests/ui/redundant_pattern_matching.fixed
+++ b/tests/ui/redundant_pattern_matching.fixed
@@ -18,39 +18,14 @@ fn main() {
 
     if Err::<i32, i32>(42).is_err() {}
 
-    if None::<()>.is_none() {}
-
-    if Some(42).is_some() {}
-
-    if Some(42).is_some() {
-        foo();
-    } else {
-        bar();
-    }
-
-    while Some(42).is_some() {}
-
-    while Some(42).is_none() {}
-
-    while None::<()>.is_none() {}
-
     while Ok::<i32, i32>(10).is_ok() {}
 
     while Ok::<i32, i32>(10).is_err() {}
 
-    let mut v = vec![1, 2, 3];
-    while v.pop().is_some() {
-        foo();
-    }
-
     if Ok::<i32, i32>(42).is_ok() {}
 
     if Err::<i32, i32>(42).is_err() {}
 
-    if None::<i32>.is_none() {}
-
-    if Some(42).is_some() {}
-
     if let Ok(x) = Ok::<i32, i32>(42) {
         println!("{}", x);
     }
@@ -63,48 +38,25 @@ fn main() {
 
     Err::<i32, i32>(42).is_ok();
 
-    Some(42).is_some();
-
-    None::<()>.is_none();
-
-    let _ = None::<()>.is_none();
-
     let _ = if Ok::<usize, ()>(4).is_ok() { true } else { false };
 
-    let opt = Some(false);
-    let x = if opt.is_some() { true } else { false };
-    takes_bool(x);
-
     issue5504();
-    issue5697();
+    issue6067();
+    issue6065();
 
-    let _ = if gen_opt().is_some() {
+    let _ = if gen_res().is_ok() {
         1
-    } else if gen_opt().is_none() {
-        2
-    } else if gen_res().is_ok() {
-        3
     } else if gen_res().is_err() {
-        4
+        2
     } else {
-        5
+        3
     };
 }
 
-fn gen_opt() -> Option<()> {
-    None
-}
-
 fn gen_res() -> Result<(), ()> {
     Ok(())
 }
 
-fn takes_bool(_: bool) {}
-
-fn foo() {}
-
-fn bar() {}
-
 macro_rules! m {
     () => {
         Some(42u32)
@@ -128,41 +80,30 @@ fn issue5504() {
     while m!().is_some() {}
 }
 
-// None of these should be linted because none of the suggested methods
-// are `const fn` without toggling a feature.
-const fn issue5697() {
-    if let Ok(_) = Ok::<i32, i32>(42) {}
-
-    if let Err(_) = Err::<i32, i32>(42) {}
-
-    if let Some(_) = Some(42) {}
-
-    if let None = None::<()> {}
+fn issue6065() {
+    macro_rules! if_let_in_macro {
+        ($pat:pat, $x:expr) => {
+            if let Some($pat) = $x {}
+        };
+    }
 
-    while let Ok(_) = Ok::<i32, i32>(10) {}
+    // shouldn't be linted
+    if_let_in_macro!(_, Some(42));
+}
 
-    while let Err(_) = Ok::<i32, i32>(10) {}
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+    if Ok::<i32, i32>(42).is_ok() {}
 
-    while let Some(_) = Some(42) {}
+    if Err::<i32, i32>(42).is_err() {}
 
-    while let None = None::<()> {}
+    while Ok::<i32, i32>(10).is_ok() {}
 
-    match Ok::<i32, i32>(42) {
-        Ok(_) => true,
-        Err(_) => false,
-    };
+    while Ok::<i32, i32>(10).is_err() {}
 
-    match Err::<i32, i32>(42) {
-        Ok(_) => false,
-        Err(_) => true,
-    };
-    match Some(42) {
-        Some(_) => true,
-        None => false,
-    };
+    Ok::<i32, i32>(42).is_ok();
 
-    match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
+    Err::<i32, i32>(42).is_err();
 }
diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs
index 4c2870e7803..09426a6e590 100644
--- a/tests/ui/redundant_pattern_matching.rs
+++ b/tests/ui/redundant_pattern_matching.rs
@@ -18,39 +18,14 @@ fn main() {
 
     if let Err(_) = Err::<i32, i32>(42) {}
 
-    if let None = None::<()> {}
-
-    if let Some(_) = Some(42) {}
-
-    if let Some(_) = Some(42) {
-        foo();
-    } else {
-        bar();
-    }
-
-    while let Some(_) = Some(42) {}
-
-    while let None = Some(42) {}
-
-    while let None = None::<()> {}
-
     while let Ok(_) = Ok::<i32, i32>(10) {}
 
     while let Err(_) = Ok::<i32, i32>(10) {}
 
-    let mut v = vec![1, 2, 3];
-    while let Some(_) = v.pop() {
-        foo();
-    }
-
     if Ok::<i32, i32>(42).is_ok() {}
 
     if Err::<i32, i32>(42).is_err() {}
 
-    if None::<i32>.is_none() {}
-
-    if Some(42).is_some() {}
-
     if let Ok(x) = Ok::<i32, i32>(42) {
         println!("{}", x);
     }
@@ -75,57 +50,25 @@ fn main() {
         Err(_) => false,
     };
 
-    match Some(42) {
-        Some(_) => true,
-        None => false,
-    };
-
-    match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
-
-    let _ = match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
-
     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
 
-    let opt = Some(false);
-    let x = if let Some(_) = opt { true } else { false };
-    takes_bool(x);
-
     issue5504();
-    issue5697();
+    issue6067();
+    issue6065();
 
-    let _ = if let Some(_) = gen_opt() {
+    let _ = if let Ok(_) = gen_res() {
         1
-    } else if let None = gen_opt() {
-        2
-    } else if let Ok(_) = gen_res() {
-        3
     } else if let Err(_) = gen_res() {
-        4
+        2
     } else {
-        5
+        3
     };
 }
 
-fn gen_opt() -> Option<()> {
-    None
-}
-
 fn gen_res() -> Result<(), ()> {
     Ok(())
 }
 
-fn takes_bool(_: bool) {}
-
-fn foo() {}
-
-fn bar() {}
-
 macro_rules! m {
     () => {
         Some(42u32)
@@ -149,25 +92,29 @@ fn issue5504() {
     while let Some(_) = m!() {}
 }
 
-// None of these should be linted because none of the suggested methods
-// are `const fn` without toggling a feature.
-const fn issue5697() {
-    if let Ok(_) = Ok::<i32, i32>(42) {}
+fn issue6065() {
+    macro_rules! if_let_in_macro {
+        ($pat:pat, $x:expr) => {
+            if let Some($pat) = $x {}
+        };
+    }
 
-    if let Err(_) = Err::<i32, i32>(42) {}
+    // shouldn't be linted
+    if_let_in_macro!(_, Some(42));
+}
 
-    if let Some(_) = Some(42) {}
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_ok` and `is_err` of `Result` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
 
-    if let None = None::<()> {}
+    if let Err(_) = Err::<i32, i32>(42) {}
 
     while let Ok(_) = Ok::<i32, i32>(10) {}
 
     while let Err(_) = Ok::<i32, i32>(10) {}
 
-    while let Some(_) = Some(42) {}
-
-    while let None = None::<()> {}
-
     match Ok::<i32, i32>(42) {
         Ok(_) => true,
         Err(_) => false,
@@ -177,13 +124,4 @@ const fn issue5697() {
         Ok(_) => false,
         Err(_) => true,
     };
-    match Some(42) {
-        Some(_) => true,
-        None => false,
-    };
-
-    match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
 }
diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr
index d3c9ceaa3d7..3473ceea00e 100644
--- a/tests/ui/redundant_pattern_matching.stderr
+++ b/tests/ui/redundant_pattern_matching.stderr
@@ -18,62 +18,20 @@ error: redundant pattern matching, consider using `is_err()`
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:21:12
-   |
-LL |     if let None = None::<()> {}
-   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:23:12
-   |
-LL |     if let Some(_) = Some(42) {}
-   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:25:12
-   |
-LL |     if let Some(_) = Some(42) {
-   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:31:15
-   |
-LL |     while let Some(_) = Some(42) {}
-   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:33:15
-   |
-LL |     while let None = Some(42) {}
-   |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:35:15
-   |
-LL |     while let None = None::<()> {}
-   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
-
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:37:15
+  --> $DIR/redundant_pattern_matching.rs:21:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:39:15
+  --> $DIR/redundant_pattern_matching.rs:23:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:42:15
-   |
-LL |     while let Some(_) = v.pop() {
-   |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
-
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:58:5
+  --> $DIR/redundant_pattern_matching.rs:33:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -82,7 +40,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:63:5
+  --> $DIR/redundant_pattern_matching.rs:38:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -91,7 +49,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:68:5
+  --> $DIR/redundant_pattern_matching.rs:43:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -100,7 +58,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:73:5
+  --> $DIR/redundant_pattern_matching.rs:48:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -108,93 +66,89 @@ LL | |         Err(_) => false,
 LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:78:5
-   |
-LL | /     match Some(42) {
-LL | |         Some(_) => true,
-LL | |         None => false,
-LL | |     };
-   | |_____^ help: try this: `Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:83:5
-   |
-LL | /     match None::<()> {
-LL | |         Some(_) => false,
-LL | |         None => true,
-LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:88:13
-   |
-LL |       let _ = match None::<()> {
-   |  _____________^
-LL | |         Some(_) => false,
-LL | |         None => true,
-LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
-
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:93:20
+  --> $DIR/redundant_pattern_matching.rs:53:20
    |
 LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:96:20
-   |
-LL |     let x = if let Some(_) = opt { true } else { false };
-   |             -------^^^^^^^------ help: try this: `if opt.is_some()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:102:20
-   |
-LL |     let _ = if let Some(_) = gen_opt() {
-   |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:104:19
-   |
-LL |     } else if let None = gen_opt() {
-   |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
-
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:106:19
+  --> $DIR/redundant_pattern_matching.rs:59:20
    |
-LL |     } else if let Ok(_) = gen_res() {
-   |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
+LL |     let _ = if let Ok(_) = gen_res() {
+   |             -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:108:19
+  --> $DIR/redundant_pattern_matching.rs:61:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:141:19
+  --> $DIR/redundant_pattern_matching.rs:84:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:142:16
+  --> $DIR/redundant_pattern_matching.rs:85:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:148:12
+  --> $DIR/redundant_pattern_matching.rs:91:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:149:15
+  --> $DIR/redundant_pattern_matching.rs:92:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
 
-error: aborting due to 29 previous errors
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:110:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:112:12
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:114:15
+   |
+LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:116:15
+   |
+LL |     while let Err(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:118:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:123:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: aborting due to 22 previous errors
 
diff --git a/tests/ui/redundant_pattern_matching_const_result.fixed b/tests/ui/redundant_pattern_matching_const_result.fixed
deleted file mode 100644
index de3fe00d5fa..00000000000
--- a/tests/ui/redundant_pattern_matching_const_result.fixed
+++ /dev/null
@@ -1,44 +0,0 @@
-// run-rustfix
-
-#![feature(const_result)]
-#![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::match_like_matches_macro, unused)]
-
-// Test that results are linted with the feature enabled.
-
-const fn issue_5697() {
-    if Ok::<i32, i32>(42).is_ok() {}
-
-    if Err::<i32, i32>(42).is_err() {}
-
-    while Ok::<i32, i32>(10).is_ok() {}
-
-    while Ok::<i32, i32>(10).is_err() {}
-
-    Ok::<i32, i32>(42).is_ok();
-
-    Err::<i32, i32>(42).is_err();
-
-    // These should not be linted until `const_option` is implemented.
-    // See https://github.com/rust-lang/rust/issues/67441
-
-    if let Some(_) = Some(42) {}
-
-    if let None = None::<()> {}
-
-    while let Some(_) = Some(42) {}
-
-    while let None = None::<()> {}
-
-    match Some(42) {
-        Some(_) => true,
-        None => false,
-    };
-
-    match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
-}
-
-fn main() {}
diff --git a/tests/ui/redundant_pattern_matching_const_result.rs b/tests/ui/redundant_pattern_matching_const_result.rs
deleted file mode 100644
index b77969d53d9..00000000000
--- a/tests/ui/redundant_pattern_matching_const_result.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-rustfix
-
-#![feature(const_result)]
-#![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::match_like_matches_macro, unused)]
-
-// Test that results are linted with the feature enabled.
-
-const fn issue_5697() {
-    if let Ok(_) = Ok::<i32, i32>(42) {}
-
-    if let Err(_) = Err::<i32, i32>(42) {}
-
-    while let Ok(_) = Ok::<i32, i32>(10) {}
-
-    while let Err(_) = Ok::<i32, i32>(10) {}
-
-    match Ok::<i32, i32>(42) {
-        Ok(_) => true,
-        Err(_) => false,
-    };
-
-    match Err::<i32, i32>(42) {
-        Ok(_) => false,
-        Err(_) => true,
-    };
-
-    // These should not be linted until `const_option` is implemented.
-    // See https://github.com/rust-lang/rust/issues/67441
-
-    if let Some(_) = Some(42) {}
-
-    if let None = None::<()> {}
-
-    while let Some(_) = Some(42) {}
-
-    while let None = None::<()> {}
-
-    match Some(42) {
-        Some(_) => true,
-        None => false,
-    };
-
-    match None::<()> {
-        Some(_) => false,
-        None => true,
-    };
-}
-
-fn main() {}
diff --git a/tests/ui/redundant_pattern_matching_const_result.stderr b/tests/ui/redundant_pattern_matching_const_result.stderr
deleted file mode 100644
index 8ecd72158d3..00000000000
--- a/tests/ui/redundant_pattern_matching_const_result.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:10:12
-   |
-LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
-   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
-   |
-   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
-
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:12:12
-   |
-LL |     if let Err(_) = Err::<i32, i32>(42) {}
-   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
-
-error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:14:15
-   |
-LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
-   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
-
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:16:15
-   |
-LL |     while let Err(_) = Ok::<i32, i32>(10) {}
-   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
-
-error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:18:5
-   |
-LL | /     match Ok::<i32, i32>(42) {
-LL | |         Ok(_) => true,
-LL | |         Err(_) => false,
-LL | |     };
-   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
-
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_const_result.rs:23:5
-   |
-LL | /     match Err::<i32, i32>(42) {
-LL | |         Ok(_) => false,
-LL | |         Err(_) => true,
-LL | |     };
-   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
-
-error: aborting due to 6 previous errors
-
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
new file mode 100644
index 00000000000..499b975b2bb
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -0,0 +1,85 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(
+    clippy::unit_arg,
+    unused_must_use,
+    clippy::needless_bool,
+    clippy::match_like_matches_macro,
+    deprecated
+)]
+
+fn main() {
+    if None::<()>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    if Some(42).is_some() {
+        foo();
+    } else {
+        bar();
+    }
+
+    while Some(42).is_some() {}
+
+    while Some(42).is_none() {}
+
+    while None::<()>.is_none() {}
+
+    let mut v = vec![1, 2, 3];
+    while v.pop().is_some() {
+        foo();
+    }
+
+    if None::<i32>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    Some(42).is_some();
+
+    None::<()>.is_none();
+
+    let _ = None::<()>.is_none();
+
+    let opt = Some(false);
+    let x = if opt.is_some() { true } else { false };
+    takes_bool(x);
+
+    issue6067();
+
+    let _ = if gen_opt().is_some() {
+        1
+    } else if gen_opt().is_none() {
+        2
+    } else {
+        3
+    };
+}
+
+fn gen_opt() -> Option<()> {
+    None
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+    if Some(42).is_some() {}
+
+    if None::<()>.is_none() {}
+
+    while Some(42).is_some() {}
+
+    while None::<()>.is_none() {}
+
+    Some(42).is_some();
+
+    None::<()>.is_none();
+}
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
new file mode 100644
index 00000000000..2a98435e790
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -0,0 +1,100 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(
+    clippy::unit_arg,
+    unused_must_use,
+    clippy::needless_bool,
+    clippy::match_like_matches_macro,
+    deprecated
+)]
+
+fn main() {
+    if let None = None::<()> {}
+
+    if let Some(_) = Some(42) {}
+
+    if let Some(_) = Some(42) {
+        foo();
+    } else {
+        bar();
+    }
+
+    while let Some(_) = Some(42) {}
+
+    while let None = Some(42) {}
+
+    while let None = None::<()> {}
+
+    let mut v = vec![1, 2, 3];
+    while let Some(_) = v.pop() {
+        foo();
+    }
+
+    if None::<i32>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+
+    let _ = match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+
+    let opt = Some(false);
+    let x = if let Some(_) = opt { true } else { false };
+    takes_bool(x);
+
+    issue6067();
+
+    let _ = if let Some(_) = gen_opt() {
+        1
+    } else if let None = gen_opt() {
+        2
+    } else {
+        3
+    };
+}
+
+fn gen_opt() -> Option<()> {
+    None
+}
+
+fn takes_bool(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+// Methods that are unstable const should not be suggested within a const context, see issue #5697.
+// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
+// so the following should be linted.
+const fn issue6067() {
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
new file mode 100644
index 00000000000..eebb3448491
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -0,0 +1,134 @@
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:14:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:16:12
+   |
+LL |     if let Some(_) = Some(42) {}
+   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:18:12
+   |
+LL |     if let Some(_) = Some(42) {
+   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:24:15
+   |
+LL |     while let Some(_) = Some(42) {}
+   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:26:15
+   |
+LL |     while let None = Some(42) {}
+   |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:28:15
+   |
+LL |     while let None = None::<()> {}
+   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:31:15
+   |
+LL |     while let Some(_) = v.pop() {
+   |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:39:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => true,
+LL | |         None => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:44:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:49:13
+   |
+LL |       let _ = match None::<()> {
+   |  _____________^
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:55:20
+   |
+LL |     let x = if let Some(_) = opt { true } else { false };
+   |             -------^^^^^^^------ help: try this: `if opt.is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:60:20
+   |
+LL |     let _ = if let Some(_) = gen_opt() {
+   |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:62:19
+   |
+LL |     } else if let None = gen_opt() {
+   |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:83:12
+   |
+LL |     if let Some(_) = Some(42) {}
+   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:85:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:87:15
+   |
+LL |     while let Some(_) = Some(42) {}
+   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:89:15
+   |
+LL |     while let None = None::<()> {}
+   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:91:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => true,
+LL | |         None => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:96:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: aborting due to 19 previous errors
+
diff --git a/tests/ui/result_map_unit_fn_fixable.stderr b/tests/ui/result_map_unit_fn_fixable.stderr
index 467e00263cd..4f3a8c6b792 100644
--- a/tests/ui/result_map_unit_fn_fixable.stderr
+++ b/tests/ui/result_map_unit_fn_fixable.stderr
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:35:5
    |
 LL |     x.field.map(do_nothing);
@@ -8,7 +8,7 @@ LL |     x.field.map(do_nothing);
    |
    = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:37:5
    |
 LL |     x.field.map(do_nothing);
@@ -16,7 +16,7 @@ LL |     x.field.map(do_nothing);
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:39:5
    |
 LL |     x.field.map(diverge);
@@ -24,7 +24,7 @@ LL |     x.field.map(diverge);
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:45:5
    |
 LL |     x.field.map(|value| x.do_result_nothing(value + captured));
@@ -32,7 +32,7 @@ LL |     x.field.map(|value| x.do_result_nothing(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:47:5
    |
 LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
@@ -40,7 +40,7 @@ LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:50:5
    |
 LL |     x.field.map(|value| do_nothing(value + captured));
@@ -48,7 +48,7 @@ LL |     x.field.map(|value| do_nothing(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:52:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured) });
@@ -56,7 +56,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:54:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured); });
@@ -64,7 +64,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:56:5
    |
 LL |     x.field.map(|value| { { do_nothing(value + captured); } });
@@ -72,7 +72,7 @@ LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:59:5
    |
 LL |     x.field.map(|value| diverge(value + captured));
@@ -80,7 +80,7 @@ LL |     x.field.map(|value| diverge(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:61:5
    |
 LL |     x.field.map(|value| { diverge(value + captured) });
@@ -88,7 +88,7 @@ LL |     x.field.map(|value| { diverge(value + captured) });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:63:5
    |
 LL |     x.field.map(|value| { diverge(value + captured); });
@@ -96,7 +96,7 @@ LL |     x.field.map(|value| { diverge(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:65:5
    |
 LL |     x.field.map(|value| { { diverge(value + captured); } });
@@ -104,7 +104,7 @@ LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:70:5
    |
 LL |     x.field.map(|value| { let y = plus_one(value + captured); });
@@ -112,7 +112,7 @@ LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:72:5
    |
 LL |     x.field.map(|value| { plus_one(value + captured); });
@@ -120,7 +120,7 @@ LL |     x.field.map(|value| { plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:74:5
    |
 LL |     x.field.map(|value| { { plus_one(value + captured); } });
@@ -128,7 +128,7 @@ LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:77:5
    |
 LL |     x.field.map(|ref value| { do_nothing(value + captured) });
diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr
index b23cc608621..88e4efdb0f0 100644
--- a/tests/ui/result_map_unit_fn_unfixable.stderr
+++ b/tests/ui/result_map_unit_fn_unfixable.stderr
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:23:5
    |
 LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
@@ -8,7 +8,7 @@ LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
    |
    = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:25:5
    |
 LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
@@ -16,7 +16,7 @@ LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value)
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:29:5
    |
 LL |        x.field.map(|value| {
@@ -30,7 +30,7 @@ LL | ||     });
    | |_______|
    | 
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:33:5
    |
 LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
@@ -38,7 +38,7 @@ LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:37:5
    |
 LL |     "12".parse::<i32>().map(diverge);
@@ -46,7 +46,7 @@ LL |     "12".parse::<i32>().map(diverge);
    |     |
    |     help: try this: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:43:5
    |
 LL |     y.map(do_nothing);
diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs
index 0928820892b..a37c8782ec3 100644
--- a/tests/ui/same_item_push.rs
+++ b/tests/ui/same_item_push.rs
@@ -1,5 +1,7 @@
 #![warn(clippy::same_item_push)]
 
+const VALUE: u8 = 7;
+
 fn mutate_increment(x: &mut u8) -> u8 {
     *x += 1;
     *x
@@ -9,65 +11,81 @@ fn increment(x: u8) -> u8 {
     x + 1
 }
 
-fn main() {
-    // Test for basic case
-    let mut spaces = Vec::with_capacity(10);
-    for _ in 0..10 {
-        spaces.push(vec![b' ']);
-    }
+fn fun() -> usize {
+    42
+}
 
-    let mut vec2: Vec<u8> = Vec::new();
+fn main() {
+    // ** linted cases **
+    let mut vec: Vec<u8> = Vec::new();
     let item = 2;
     for _ in 5..=20 {
-        vec2.push(item);
+        vec.push(item);
     }
 
-    let mut vec3: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for _ in 0..15 {
         let item = 2;
-        vec3.push(item);
+        vec.push(item);
     }
 
-    let mut vec4: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for _ in 0..15 {
-        vec4.push(13);
+        vec.push(13);
+    }
+
+    let mut vec = Vec::new();
+    for _ in 0..20 {
+        vec.push(VALUE);
+    }
+
+    let mut vec = Vec::new();
+    let item = VALUE;
+    for _ in 0..20 {
+        vec.push(item);
+    }
+
+    // ** non-linted cases **
+    let mut spaces = Vec::with_capacity(10);
+    for _ in 0..10 {
+        spaces.push(vec![b' ']);
     }
 
     // Suggestion should not be given as pushed variable can mutate
-    let mut vec5: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item: u8 = 2;
     for _ in 0..30 {
-        vec5.push(mutate_increment(&mut item));
+        vec.push(mutate_increment(&mut item));
     }
 
-    let mut vec6: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item: u8 = 2;
     let mut item2 = &mut mutate_increment(&mut item);
     for _ in 0..30 {
-        vec6.push(mutate_increment(item2));
+        vec.push(mutate_increment(item2));
     }
 
-    let mut vec7: Vec<usize> = Vec::new();
+    let mut vec: Vec<usize> = Vec::new();
     for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() {
-        vec7.push(a);
+        vec.push(a);
     }
 
-    let mut vec8: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for i in 0..30 {
-        vec8.push(increment(i));
+        vec.push(increment(i));
     }
 
-    let mut vec9: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for i in 0..30 {
-        vec9.push(i + i * i);
+        vec.push(i + i * i);
     }
 
     // Suggestion should not be given as there are multiple pushes that are not the same
-    let mut vec10: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let item: u8 = 2;
     for _ in 0..30 {
-        vec10.push(item);
-        vec10.push(item * 2);
+        vec.push(item);
+        vec.push(item * 2);
     }
 
     // Suggestion should not be given as Vec is not involved
@@ -82,23 +100,23 @@ fn main() {
     for i in 0..30 {
         vec_a.push(A { kind: i });
     }
-    let mut vec12: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for a in vec_a {
-        vec12.push(2u8.pow(a.kind));
+        vec.push(2u8.pow(a.kind));
     }
 
     // Fix #5902
-    let mut vec13: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item = 0;
     for _ in 0..10 {
-        vec13.push(item);
+        vec.push(item);
         item += 10;
     }
 
     // Fix #5979
-    let mut vec14: Vec<std::fs::File> = Vec::new();
+    let mut vec: Vec<std::fs::File> = Vec::new();
     for _ in 0..10 {
-        vec14.push(std::fs::File::open("foobar").unwrap());
+        vec.push(std::fs::File::open("foobar").unwrap());
     }
     // Fix #5979
     #[derive(Clone)]
@@ -107,8 +125,27 @@ fn main() {
     trait T {}
     impl T for S {}
 
-    let mut vec15: Vec<Box<dyn T>> = Vec::new();
+    let mut vec: Vec<Box<dyn T>> = Vec::new();
     for _ in 0..10 {
-        vec15.push(Box::new(S {}));
+        vec.push(Box::new(S {}));
+    }
+
+    // Fix #5985
+    let mut vec = Vec::new();
+    let item = 42;
+    let item = fun();
+    for _ in 0..20 {
+        vec.push(item);
+    }
+
+    // Fix #5985
+    let mut vec = Vec::new();
+    let key = 1;
+    for _ in 0..20 {
+        let item = match key {
+            1 => 10,
+            _ => 0,
+        };
+        vec.push(item);
     }
 }
diff --git a/tests/ui/same_item_push.stderr b/tests/ui/same_item_push.stderr
index ddc5d48cd41..d9ffa15780a 100644
--- a/tests/ui/same_item_push.stderr
+++ b/tests/ui/same_item_push.stderr
@@ -1,35 +1,43 @@
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:16:9
+  --> $DIR/same_item_push.rs:23:9
    |
-LL |         spaces.push(vec![b' ']);
-   |         ^^^^^^
+LL |         vec.push(item);
+   |         ^^^
    |
    = note: `-D clippy::same-item-push` implied by `-D warnings`
-   = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' '])
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:22:9
+  --> $DIR/same_item_push.rs:29:9
    |
-LL |         vec2.push(item);
-   |         ^^^^
+LL |         vec.push(item);
+   |         ^^^
    |
-   = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item)
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:28:9
+  --> $DIR/same_item_push.rs:34:9
    |
-LL |         vec3.push(item);
-   |         ^^^^
+LL |         vec.push(13);
+   |         ^^^
    |
-   = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item)
+   = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:33:9
+  --> $DIR/same_item_push.rs:39:9
    |
-LL |         vec4.push(13);
-   |         ^^^^
+LL |         vec.push(VALUE);
+   |         ^^^
    |
-   = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13)
+   = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE)
 
-error: aborting due to 4 previous errors
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:45:9
+   |
+LL |         vec.push(item);
+   |         ^^^
+   |
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
+
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs
index c6c315d5fab..ac4c1bc6597 100644
--- a/tests/ui/temporary_assignment.rs
+++ b/tests/ui/temporary_assignment.rs
@@ -53,11 +53,6 @@ fn main() {
     ArrayStruct { array: [0] }.array[0] = 1;
     (0, 0).0 = 1;
 
-    A.0 = 2;
-    B.field = 2;
-    C.structure.field = 2;
-    D.array[0] = 2;
-
     // no error
     s.field = 1;
     t.0 = 1;
diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr
index 4efe2d4bb67..7d79901a28d 100644
--- a/tests/ui/temporary_assignment.stderr
+++ b/tests/ui/temporary_assignment.stderr
@@ -28,29 +28,5 @@ error: assignment to temporary
 LL |     (0, 0).0 = 1;
    |     ^^^^^^^^^^^^
 
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:56:5
-   |
-LL |     A.0 = 2;
-   |     ^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:57:5
-   |
-LL |     B.field = 2;
-   |     ^^^^^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:58:5
-   |
-LL |     C.structure.field = 2;
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:59:5
-   |
-LL |     D.array[0] = 2;
-   |     ^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs
index 1cef8c2cfc9..fbdc977b769 100644
--- a/tests/ui/trailing_zeros.rs
+++ b/tests/ui/trailing_zeros.rs
@@ -1,4 +1,5 @@
 #![allow(unused_parens)]
+#![warn(clippy::verbose_bit_mask)]
 
 fn main() {
     let x: i32 = 42;
diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr
index 320d9cc3f64..79855111830 100644
--- a/tests/ui/trailing_zeros.stderr
+++ b/tests/ui/trailing_zeros.stderr
@@ -1,5 +1,5 @@
 error: bit mask could be simplified with a call to `trailing_zeros`
-  --> $DIR/trailing_zeros.rs:5:13
+  --> $DIR/trailing_zeros.rs:6:13
    |
 LL |     let _ = (x & 0b1111 == 0); // suggest trailing_zeros
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
@@ -7,7 +7,7 @@ LL |     let _ = (x & 0b1111 == 0); // suggest trailing_zeros
    = note: `-D clippy::verbose-bit-mask` implied by `-D warnings`
 
 error: bit mask could be simplified with a call to `trailing_zeros`
-  --> $DIR/trailing_zeros.rs:6:13
+  --> $DIR/trailing_zeros.rs:7:13
    |
 LL |     let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5`
diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs
index 2992abae775..fec115ff29d 100644
--- a/tests/ui/unit_arg.rs
+++ b/tests/ui/unit_arg.rs
@@ -1,5 +1,11 @@
 #![warn(clippy::unit_arg)]
-#![allow(clippy::no_effect, unused_must_use, unused_variables)]
+#![allow(
+    clippy::no_effect,
+    unused_must_use,
+    unused_variables,
+    clippy::unused_unit,
+    clippy::or_fun_call
+)]
 
 use std::fmt::Debug;
 
@@ -47,6 +53,11 @@ fn bad() {
             foo(3);
         },
     );
+    // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block
+    None.or(Some(foo(2)));
+    // in this case, the suggestion can be inlined, no need for a surrounding block
+    // foo(()); foo(()) instead of { foo(()); foo(()) }
+    foo(foo(()))
 }
 
 fn ok() {
diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr
index 56f6a855dfa..90fee3aab23 100644
--- a/tests/ui/unit_arg.stderr
+++ b/tests/ui/unit_arg.stderr
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:23:5
+  --> $DIR/unit_arg.rs:29:5
    |
 LL | /     foo({
 LL | |         1;
@@ -11,34 +11,28 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         1
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         1;
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:26:5
+  --> $DIR/unit_arg.rs:32:5
    |
 LL |     foo(foo(1));
    |     ^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     foo(1);
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:27:5
+  --> $DIR/unit_arg.rs:33:5
    |
 LL | /     foo({
 LL | |         foo(1);
@@ -50,20 +44,17 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         foo(2)
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         foo(1);
 LL |         foo(2);
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:32:5
+  --> $DIR/unit_arg.rs:38:5
    |
 LL | /     b.bar({
 LL | |         1;
@@ -74,35 +65,29 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         1
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         1;
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     b.bar(());
-   |           ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:35:5
+  --> $DIR/unit_arg.rs:41:5
    |
 LL |     taking_multiple_units(foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expressions in front of the call...
+help: move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     foo(1);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_multiple_units((), ());
-   |                           ^^  ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:36:5
+  --> $DIR/unit_arg.rs:42:5
    |
 LL | /     taking_multiple_units(foo(0), {
 LL | |         foo(1);
@@ -114,21 +99,18 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         foo(2)
    |
-help: or move the expressions in front of the call...
+help: or move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     {
 LL |         foo(1);
 LL |         foo(2);
 LL |     };
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_multiple_units((), ());
-   |                           ^^  ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:40:5
+  --> $DIR/unit_arg.rs:46:5
    |
 LL | /     taking_multiple_units(
 LL | |         {
@@ -147,7 +129,7 @@ help: remove the semicolon from the last statement in the block
    |
 LL |             foo(3)
    |
-help: or move the expressions in front of the call...
+help: or move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     {
 LL |         foo(0);
@@ -156,26 +138,44 @@ LL |     };
 LL |     {
 LL |         foo(2);
  ...
-help: ...and use unit literals instead
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:57:13
+   |
+LL |     None.or(Some(foo(2)));
+   |             ^^^^^^^^^^^^
    |
-LL |         (),
-LL |         (),
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL |     None.or({
+LL |         foo(2);
+LL |         Some(())
+LL |     });
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:82:5
+  --> $DIR/unit_arg.rs:60:5
    |
-LL |     Some(foo(1))
+LL |     foo(foo(()))
    |     ^^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
-LL |     foo(1);
+LL |     foo(());
+LL |     foo(())
    |
-help: ...and use a unit literal instead
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:93:5
    |
+LL |     Some(foo(1))
+   |     ^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL |     foo(1);
 LL |     Some(())
-   |          ^^
+   |
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr
index bb58483584b..456b12a2c6b 100644
--- a/tests/ui/unit_arg_empty_blocks.stderr
+++ b/tests/ui/unit_arg_empty_blocks.stderr
@@ -22,14 +22,11 @@ error: passing unit values to a function
 LL |     taking_two_units({}, foo(0));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     foo(0);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_two_units((), ());
-   |                      ^^  ^^
+   |
 
 error: passing unit values to a function
   --> $DIR/unit_arg_empty_blocks.rs:18:5
@@ -37,15 +34,12 @@ error: passing unit values to a function
 LL |     taking_three_units({}, foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expressions in front of the call...
+help: move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     foo(1);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_three_units((), (), ());
-   |                        ^^  ^^  ^^
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed
index fa66e68794e..4ba2a0a5dbc 100644
--- a/tests/ui/unnecessary_lazy_eval.fixed
+++ b/tests/ui/unnecessary_lazy_eval.fixed
@@ -2,6 +2,7 @@
 #![warn(clippy::unnecessary_lazy_evaluations)]
 #![allow(clippy::redundant_closure)]
 #![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::map_identity)]
 
 struct Deep(Option<usize>);
 
@@ -34,13 +35,13 @@ fn main() {
     let _ = opt.unwrap_or(2);
     let _ = opt.unwrap_or(astronomers_pi);
     let _ = opt.unwrap_or(ext_str.some_field);
-    let _ = opt.unwrap_or(ext_arr[0]);
+    let _ = opt.unwrap_or_else(|| ext_arr[0]);
     let _ = opt.and(ext_opt);
     let _ = opt.or(ext_opt);
     let _ = opt.or(None);
     let _ = opt.get_or_insert(2);
     let _ = opt.ok_or(2);
-    let _ = opt.ok_or(ext_arr[0]);
+    let _ = nested_tuple_opt.unwrap_or(Some((1, 2)));
 
     // Cases when unwrap is not called on a simple variable
     let _ = Some(10).unwrap_or(2);
@@ -60,7 +61,6 @@ fn main() {
     // Should not lint - Option
     let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
     let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
-    let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
     let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
     let _ = opt.or_else(some_call);
     let _ = opt.or_else(|| some_call());
@@ -69,13 +69,16 @@ fn main() {
     let _ = deep.0.get_or_insert_with(|| some_call());
     let _ = deep.0.or_else(some_call);
     let _ = deep.0.or_else(|| some_call());
+    let _ = opt.ok_or_else(|| ext_arr[0]);
 
-    // These are handled by bind_instead_of_map
+    // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
     let _ = Some(10).and_then(|idx| Some(idx));
-    let _: Option<usize> = None.or_else(|| Some(3));
-    let _ = deep.0.or_else(|| Some(3));
-    let _ = opt.or_else(|| Some(3));
+
+    // should lint, bind_instead_of_map doesn't apply
+    let _: Option<usize> = None.or(Some(3));
+    let _ = deep.0.or(Some(3));
+    let _ = opt.or(Some(3));
 
     // Should lint - Result
     let res: Result<usize, usize> = Err(5);
@@ -92,26 +95,28 @@ fn main() {
     let _ = res2.unwrap_or_else(|err| err.return_some_field());
     let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
 
+    // should not lint, bind_instead_of_map takes priority
     let _: Result<usize, usize> = res.and_then(|x| Ok(x));
-    let _: Result<usize, usize> = res.and_then(|x| Err(x));
-
-    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
     let _: Result<usize, usize> = res.or_else(|err| Err(err));
 
-    // These are handled by bind_instead_of_map
     let _: Result<usize, usize> = res.and_then(|_| Ok(2));
     let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
     let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
 
-    let _: Result<usize, usize> = res.and_then(|_| Err(2));
-    let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
-    let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
-
-    let _: Result<usize, usize> = res.or_else(|_| Ok(2));
-    let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
-    let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
-
     let _: Result<usize, usize> = res.or_else(|_| Err(2));
     let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
     let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+
+    // should lint, bind_instead_of_map doesn't apply
+    let _: Result<usize, usize> = res.and(Err(2));
+    let _: Result<usize, usize> = res.and(Err(astronomers_pi));
+    let _: Result<usize, usize> = res.and(Err(ext_str.some_field));
+
+    let _: Result<usize, usize> = res.or(Ok(2));
+    let _: Result<usize, usize> = res.or(Ok(astronomers_pi));
+    let _: Result<usize, usize> = res.or(Ok(ext_str.some_field));
+
+    // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
+    let _: Result<usize, usize> = res.and_then(|x| Err(x));
+    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
 }
diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs
index 04f47d1aa29..466915217e4 100644
--- a/tests/ui/unnecessary_lazy_eval.rs
+++ b/tests/ui/unnecessary_lazy_eval.rs
@@ -2,6 +2,7 @@
 #![warn(clippy::unnecessary_lazy_evaluations)]
 #![allow(clippy::redundant_closure)]
 #![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::map_identity)]
 
 struct Deep(Option<usize>);
 
@@ -40,7 +41,7 @@ fn main() {
     let _ = opt.or_else(|| None);
     let _ = opt.get_or_insert_with(|| 2);
     let _ = opt.ok_or_else(|| 2);
-    let _ = opt.ok_or_else(|| ext_arr[0]);
+    let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
 
     // Cases when unwrap is not called on a simple variable
     let _ = Some(10).unwrap_or_else(|| 2);
@@ -60,7 +61,6 @@ fn main() {
     // Should not lint - Option
     let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
     let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
-    let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
     let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
     let _ = opt.or_else(some_call);
     let _ = opt.or_else(|| some_call());
@@ -69,10 +69,13 @@ fn main() {
     let _ = deep.0.get_or_insert_with(|| some_call());
     let _ = deep.0.or_else(some_call);
     let _ = deep.0.or_else(|| some_call());
+    let _ = opt.ok_or_else(|| ext_arr[0]);
 
-    // These are handled by bind_instead_of_map
+    // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
     let _ = Some(10).and_then(|idx| Some(idx));
+
+    // should lint, bind_instead_of_map doesn't apply
     let _: Option<usize> = None.or_else(|| Some(3));
     let _ = deep.0.or_else(|| Some(3));
     let _ = opt.or_else(|| Some(3));
@@ -92,17 +95,19 @@ fn main() {
     let _ = res2.unwrap_or_else(|err| err.return_some_field());
     let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
 
+    // should not lint, bind_instead_of_map takes priority
     let _: Result<usize, usize> = res.and_then(|x| Ok(x));
-    let _: Result<usize, usize> = res.and_then(|x| Err(x));
-
-    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
     let _: Result<usize, usize> = res.or_else(|err| Err(err));
 
-    // These are handled by bind_instead_of_map
     let _: Result<usize, usize> = res.and_then(|_| Ok(2));
     let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
     let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
 
+    let _: Result<usize, usize> = res.or_else(|_| Err(2));
+    let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
+    let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+
+    // should lint, bind_instead_of_map doesn't apply
     let _: Result<usize, usize> = res.and_then(|_| Err(2));
     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
@@ -111,7 +116,7 @@ fn main() {
     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
 
-    let _: Result<usize, usize> = res.or_else(|_| Err(2));
-    let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
-    let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
+    // neither bind_instead_of_map nor unnecessary_lazy_eval applies here
+    let _: Result<usize, usize> = res.and_then(|x| Err(x));
+    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
 }
diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr
index 5c1b2eb1f14..44dcd0cafbb 100644
--- a/tests/ui/unnecessary_lazy_eval.stderr
+++ b/tests/ui/unnecessary_lazy_eval.stderr
@@ -1,5 +1,5 @@
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:34:13
+  --> $DIR/unnecessary_lazy_eval.rs:35:13
    |
 LL |     let _ = opt.unwrap_or_else(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)`
@@ -7,142 +7,190 @@ LL |     let _ = opt.unwrap_or_else(|| 2);
    = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:35:13
+  --> $DIR/unnecessary_lazy_eval.rs:36:13
    |
 LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:36:13
+  --> $DIR/unnecessary_lazy_eval.rs:37:13
    |
 LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:37:13
-   |
-LL |     let _ = opt.unwrap_or_else(|| ext_arr[0]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])`
-
-error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:38:13
+  --> $DIR/unnecessary_lazy_eval.rs:39:13
    |
 LL |     let _ = opt.and_then(|_| ext_opt);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:39:13
+  --> $DIR/unnecessary_lazy_eval.rs:40:13
    |
 LL |     let _ = opt.or_else(|| ext_opt);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:40:13
+  --> $DIR/unnecessary_lazy_eval.rs:41:13
    |
 LL |     let _ = opt.or_else(|| None);
    |             ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:41:13
+  --> $DIR/unnecessary_lazy_eval.rs:42:13
    |
 LL |     let _ = opt.get_or_insert_with(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:42:13
+  --> $DIR/unnecessary_lazy_eval.rs:43:13
    |
 LL |     let _ = opt.ok_or_else(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:43:13
+  --> $DIR/unnecessary_lazy_eval.rs:44:13
    |
-LL |     let _ = opt.ok_or_else(|| ext_arr[0]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])`
+LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:46:13
+  --> $DIR/unnecessary_lazy_eval.rs:47:13
    |
 LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:47:13
+  --> $DIR/unnecessary_lazy_eval.rs:48:13
    |
 LL |     let _ = Some(10).and_then(|_| ext_opt);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:48:28
+  --> $DIR/unnecessary_lazy_eval.rs:49:28
    |
 LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:49:13
+  --> $DIR/unnecessary_lazy_eval.rs:50:13
    |
 LL |     let _ = None.get_or_insert_with(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:50:35
+  --> $DIR/unnecessary_lazy_eval.rs:51:35
    |
 LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                   ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:51:28
+  --> $DIR/unnecessary_lazy_eval.rs:52:28
    |
 LL |     let _: Option<usize> = None.or_else(|| None);
    |                            ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:54:13
+  --> $DIR/unnecessary_lazy_eval.rs:55:13
    |
 LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:55:13
+  --> $DIR/unnecessary_lazy_eval.rs:56:13
    |
 LL |     let _ = deep.0.and_then(|_| ext_opt);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:56:13
+  --> $DIR/unnecessary_lazy_eval.rs:57:13
    |
 LL |     let _ = deep.0.or_else(|| None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:57:13
+  --> $DIR/unnecessary_lazy_eval.rs:58:13
    |
 LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:58:13
+  --> $DIR/unnecessary_lazy_eval.rs:59:13
    |
 LL |     let _ = deep.0.ok_or_else(|| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)`
 
+error: unnecessary closure used to substitute value for `Option::None`
+  --> $DIR/unnecessary_lazy_eval.rs:79:28
+   |
+LL |     let _: Option<usize> = None.or_else(|| Some(3));
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))`
+
+error: unnecessary closure used to substitute value for `Option::None`
+  --> $DIR/unnecessary_lazy_eval.rs:80:13
+   |
+LL |     let _ = deep.0.or_else(|| Some(3));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))`
+
+error: unnecessary closure used to substitute value for `Option::None`
+  --> $DIR/unnecessary_lazy_eval.rs:81:13
+   |
+LL |     let _ = opt.or_else(|| Some(3));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))`
+
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:84:13
+  --> $DIR/unnecessary_lazy_eval.rs:87:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| 2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:85:13
+  --> $DIR/unnecessary_lazy_eval.rs:88:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:86:13
+  --> $DIR/unnecessary_lazy_eval.rs:89:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)`
 
-error: aborting due to 24 previous errors
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:111:35
+   |
+LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:112:35
+   |
+LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:113:35
+   |
+LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:115:35
+   |
+LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:116:35
+   |
+LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))`
+
+error: unnecessary closure used to substitute value for `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:117:35
+   |
+LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))`
+
+error: aborting due to 32 previous errors
 
diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed
index 31c2ba0f9c5..ad0d0387db0 100644
--- a/tests/ui/unnecessary_sort_by.fixed
+++ b/tests/ui/unnecessary_sort_by.fixed
@@ -25,17 +25,25 @@ fn unnecessary_sort_by() {
     vec.sort_by(|_, b| b.cmp(&5));
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
+
+    // Ignore vectors of references
+    let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
+    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_unstable_by(|a, b| b.cmp(a));
 }
 
-// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
 mod issue_5754 {
-    struct Test(String);
+    #[derive(Clone, Copy)]
+    struct Test(usize);
 
     #[derive(PartialOrd, Ord, PartialEq, Eq)]
-    struct Wrapper<'a>(&'a str);
+    struct Wrapper<'a>(&'a usize);
 
     impl Test {
-        fn name(&self) -> &str {
+        fn name(&self) -> &usize {
             &self.0
         }
 
@@ -60,7 +68,33 @@ mod issue_5754 {
     }
 }
 
+// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
+// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
+// not linted.
+mod issue_6001 {
+    struct Test(String);
+
+    impl Test {
+        // Return an owned type so that we don't hit the fix for 5754
+        fn name(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+    }
+}
+
 fn main() {
     unnecessary_sort_by();
     issue_5754::test();
+    issue_6001::test();
 }
diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs
index a3c8ae468ed..9746f6e6849 100644
--- a/tests/ui/unnecessary_sort_by.rs
+++ b/tests/ui/unnecessary_sort_by.rs
@@ -25,17 +25,25 @@ fn unnecessary_sort_by() {
     vec.sort_by(|_, b| b.cmp(&5));
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
+
+    // Ignore vectors of references
+    let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
+    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_unstable_by(|a, b| b.cmp(a));
 }
 
-// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
 mod issue_5754 {
-    struct Test(String);
+    #[derive(Clone, Copy)]
+    struct Test(usize);
 
     #[derive(PartialOrd, Ord, PartialEq, Eq)]
-    struct Wrapper<'a>(&'a str);
+    struct Wrapper<'a>(&'a usize);
 
     impl Test {
-        fn name(&self) -> &str {
+        fn name(&self) -> &usize {
             &self.0
         }
 
@@ -60,7 +68,33 @@ mod issue_5754 {
     }
 }
 
+// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
+// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
+// not linted.
+mod issue_6001 {
+    struct Test(String);
+
+    impl Test {
+        // Return an owned type so that we don't hit the fix for 5754
+        fn name(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+    }
+}
+
 fn main() {
     unnecessary_sort_by();
     issue_5754::test();
+    issue_6001::test();
 }
diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr
index f1e880d2696..11c6efb25cc 100644
--- a/tests/ui/useless_conversion.stderr
+++ b/tests/ui/useless_conversion.stderr
@@ -1,4 +1,4 @@
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
   --> $DIR/useless_conversion.rs:6:13
    |
 LL |     let _ = T::from(val);
@@ -10,61 +10,61 @@ note: the lint level is defined here
 LL | #![deny(clippy::useless_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
   --> $DIR/useless_conversion.rs:7:5
    |
 LL |     val.into()
    |     ^^^^^^^^^^ help: consider removing `.into()`: `val`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `i32`
   --> $DIR/useless_conversion.rs:19:22
    |
 LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion.rs:60:21
    |
 LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion.rs:61:21
    |
 LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion.rs:62:13
    |
 LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion.rs:63:13
    |
 LL |     let _ = String::from(format!("A: {:04}", 123));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::str::Lines`
   --> $DIR/useless_conversion.rs:64:13
    |
 LL |     let _ = "".lines().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::vec::IntoIter<i32>`
   --> $DIR/useless_conversion.rs:65:13
    |
 LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion.rs:66:21
    |
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `i32`
   --> $DIR/useless_conversion.rs:71:13
    |
 LL |     let _ = i32::from(a + b) * 3;
diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr
index b765727c168..2e0d9129bfb 100644
--- a/tests/ui/useless_conversion_try.stderr
+++ b/tests/ui/useless_conversion_try.stderr
@@ -1,4 +1,4 @@
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
   --> $DIR/useless_conversion_try.rs:6:13
    |
 LL |     let _ = T::try_from(val).unwrap();
@@ -11,7 +11,7 @@ LL | #![deny(clippy::useless_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: consider removing `T::try_from()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `T`
   --> $DIR/useless_conversion_try.rs:7:5
    |
 LL |     val.try_into().unwrap()
@@ -19,7 +19,7 @@ LL |     val.try_into().unwrap()
    |
    = help: consider removing `.try_into()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:29:21
    |
 LL |     let _: String = "foo".to_string().try_into().unwrap();
@@ -27,7 +27,7 @@ LL |     let _: String = "foo".to_string().try_into().unwrap();
    |
    = help: consider removing `.try_into()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:30:21
    |
 LL |     let _: String = TryFrom::try_from("foo".to_string()).unwrap();
@@ -35,7 +35,7 @@ LL |     let _: String = TryFrom::try_from("foo".to_string()).unwrap();
    |
    = help: consider removing `TryFrom::try_from()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:31:13
    |
 LL |     let _ = String::try_from("foo".to_string()).unwrap();
@@ -43,7 +43,7 @@ LL |     let _ = String::try_from("foo".to_string()).unwrap();
    |
    = help: consider removing `String::try_from()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:32:13
    |
 LL |     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
@@ -51,7 +51,7 @@ LL |     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
    |
    = help: consider removing `String::try_from()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:33:21
    |
 LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
@@ -59,7 +59,7 @@ LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
    |
    = help: consider removing `.try_into()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:34:21
    |
 LL |     let _: String = "".to_owned().try_into().unwrap();
@@ -67,7 +67,7 @@ LL |     let _: String = "".to_owned().try_into().unwrap();
    |
    = help: consider removing `.try_into()`
 
-error: useless conversion to the same type
+error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:35:27
    |
 LL |     let _: String = match String::from("_").try_into() {
diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs
index 93afd73d111..1c1b1b58402 100644
--- a/tests/ui/write_with_newline.rs
+++ b/tests/ui/write_with_newline.rs
@@ -14,6 +14,7 @@ fn main() {
     write!(&mut v, "Hello {}\n", "world");
     write!(&mut v, "Hello {} {}\n", "world", "#2");
     write!(&mut v, "{}\n", 1265);
+    write!(&mut v, "\n");
 
     // These should be fine
     write!(&mut v, "");
diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr
index 2473329ca72..a14e86122ee 100644
--- a/tests/ui/write_with_newline.stderr
+++ b/tests/ui/write_with_newline.stderr
@@ -44,7 +44,18 @@ LL |     writeln!(&mut v, "{}", 1265);
    |     ^^^^^^^            --
 
 error: using `write!()` with a format string that ends in a single newline
-  --> $DIR/write_with_newline.rs:35:5
+  --> $DIR/write_with_newline.rs:17:5
+   |
+LL |     write!(&mut v, "/n");
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `writeln!()` instead
+   |
+LL |     writeln!(&mut v, );
+   |     ^^^^^^^         --
+
+error: using `write!()` with a format string that ends in a single newline
+  --> $DIR/write_with_newline.rs:36:5
    |
 LL |     write!(&mut v, "//n"); // should fail
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +66,7 @@ LL |     writeln!(&mut v, "/"); // should fail
    |     ^^^^^^^            --
 
 error: using `write!()` with a format string that ends in a single newline
-  --> $DIR/write_with_newline.rs:42:5
+  --> $DIR/write_with_newline.rs:43:5
    |
 LL | /     write!(
 LL | |         &mut v,
@@ -72,7 +83,7 @@ LL |         ""
    |
 
 error: using `write!()` with a format string that ends in a single newline
-  --> $DIR/write_with_newline.rs:47:5
+  --> $DIR/write_with_newline.rs:48:5
    |
 LL | /     write!(
 LL | |         &mut v,
@@ -89,7 +100,7 @@ LL |         r""
    |
 
 error: using `write!()` with a format string that ends in a single newline
-  --> $DIR/write_with_newline.rs:56:5
+  --> $DIR/write_with_newline.rs:57:5
    |
 LL |     write!(&mut v, "/r/n"); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +111,7 @@ LL |     writeln!(&mut v, "/r"); //~ ERROR
    |     ^^^^^^^             --
 
 error: using `write!()` with a format string that ends in a single newline
-  --> $DIR/write_with_newline.rs:57:5
+  --> $DIR/write_with_newline.rs:58:5
    |
 LL |     write!(&mut v, "foo/rbar/n");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,5 +121,5 @@ help: use `writeln!()` instead
 LL |     writeln!(&mut v, "foo/rbar");
    |     ^^^^^^^                  --
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/triagebot.toml b/triagebot.toml
index 411229935c3..ed3c83af616 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1,6 +1,6 @@
 [relabel]
 allow-unauthenticated = [
-    "C-*", "A-*", "E-*", "L-*", "M-*", "O-*",
+    "C-*", "A-*", "E-*", "L-*", "M-*", "O-*", "S-*",
     "good first issue", "needs test"
 ]