about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Broto <ebroto@tutanota.com>2020-08-22 00:53:03 +0200
committerEduardo Broto <ebroto@tutanota.com>2020-08-22 00:53:03 +0200
commitc2799c861d351f79702c02c0ecb4fae0773df548 (patch)
treeb156a1ce6bd2ff3eeb059660682e7f22b98ddd8f
parent191b0806d2decdb28e610c4ee8b42cb850798246 (diff)
parent410461191393e2339e79b33fa8baf4650b905db0 (diff)
downloadrust-c2799c861d351f79702c02c0ecb4fae0773df548.tar.gz
rust-c2799c861d351f79702c02c0ecb4fae0773df548.zip
Merge remote-tracking branch 'upstream/master' into sync-from-rust
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml4
-rw-r--r--clippy_lints/Cargo.toml4
-rw-r--r--clippy_lints/src/assign_ops.rs14
-rw-r--r--clippy_lints/src/attrs.rs2
-rw-r--r--clippy_lints/src/booleans.rs10
-rw-r--r--clippy_lints/src/copies.rs7
-rw-r--r--clippy_lints/src/doc.rs75
-rw-r--r--clippy_lints/src/double_comparison.rs5
-rw-r--r--clippy_lints/src/duration_subsec.rs2
-rw-r--r--clippy_lints/src/enum_clike.rs2
-rw-r--r--clippy_lints/src/enum_variants.rs6
-rw-r--r--clippy_lints/src/eq_op.rs4
-rw-r--r--clippy_lints/src/floating_point_arithmetic.rs24
-rw-r--r--clippy_lints/src/if_let_some_result.rs4
-rw-r--r--clippy_lints/src/if_not_else.rs4
-rw-r--r--clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--clippy_lints/src/inherent_impl.rs4
-rw-r--r--clippy_lints/src/int_plus_one.rs6
-rw-r--r--clippy_lints/src/let_and_return.rs124
-rw-r--r--clippy_lints/src/lib.rs36
-rw-r--r--clippy_lints/src/loops.rs30
-rw-r--r--clippy_lints/src/map_clone.rs12
-rw-r--r--clippy_lints/src/match_on_vec_items.rs2
-rw-r--r--clippy_lints/src/methods/mod.rs302
-rw-r--r--clippy_lints/src/methods/unnecessary_lazy_eval.rs111
-rw-r--r--clippy_lints/src/misc.rs3
-rw-r--r--clippy_lints/src/mut_reference.rs17
-rw-r--r--clippy_lints/src/mutex_atomic.rs4
-rw-r--r--clippy_lints/src/precedence.rs59
-rw-r--r--clippy_lints/src/ptr.rs17
-rw-r--r--clippy_lints/src/question_mark.rs6
-rw-r--r--clippy_lints/src/returns.rs417
-rw-r--r--clippy_lints/src/self_assignment.rs51
-rw-r--r--clippy_lints/src/stable_sort_primitive.rs6
-rw-r--r--clippy_lints/src/suspicious_trait_impl.rs10
-rw-r--r--clippy_lints/src/swap.rs14
-rw-r--r--clippy_lints/src/to_string_in_display.rs100
-rw-r--r--clippy_lints/src/transmute.rs10
-rw-r--r--clippy_lints/src/try_err.rs6
-rw-r--r--clippy_lints/src/types.rs15
-rw-r--r--clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--clippy_lints/src/unused_unit.rs144
-rw-r--r--clippy_lints/src/use_self.rs2
-rw-r--r--clippy_lints/src/useless_conversion.rs5
-rw-r--r--clippy_lints/src/utils/ast_utils.rs2
-rw-r--r--clippy_lints/src/utils/author.rs21
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/utils/higher.rs76
-rw-r--r--clippy_lints/src/utils/hir_utils.rs45
-rw-r--r--clippy_lints/src/utils/internal_lints.rs5
-rw-r--r--clippy_lints/src/utils/mod.rs2
-rw-r--r--clippy_lints/src/utils/paths.rs1
-rw-r--r--clippy_lints/src/vec.rs97
-rw-r--r--clippy_lints/src/write.rs16
-rw-r--r--doc/adding_lints.md6
-rw-r--r--src/lintlist/mod.rs34
-rw-r--r--tests/ui/duration_subsec.stderr10
-rw-r--r--tests/ui/enum_clike_unportable_variant.stderr18
-rw-r--r--tests/ui/enum_variants.stderr20
-rw-r--r--tests/ui/if_let_some_result.stderr8
-rw-r--r--tests/ui/if_not_else.stderr4
-rw-r--r--tests/ui/impl.stderr8
-rw-r--r--tests/ui/implicit_saturating_sub.stderr46
-rw-r--r--tests/ui/int_plus_one.stderr8
-rw-r--r--tests/ui/iter_next_slice.stderr8
-rw-r--r--tests/ui/map_clone.stderr24
-rw-r--r--tests/ui/methods.rs68
-rw-r--r--tests/ui/methods.stderr36
-rw-r--r--tests/ui/mut_reference.stderr6
-rw-r--r--tests/ui/mutex_atomic.stderr14
-rw-r--r--tests/ui/needless_doc_main.rs68
-rw-r--r--tests/ui/needless_doc_main.stderr12
-rw-r--r--tests/ui/needless_return.fixed17
-rw-r--r--tests/ui/needless_return.rs17
-rw-r--r--tests/ui/needless_return.stderr14
-rw-r--r--tests/ui/precedence.fixed8
-rw-r--r--tests/ui/precedence.rs8
-rw-r--r--tests/ui/precedence.stderr20
-rw-r--r--tests/ui/redundant_allocation.fixed2
-rw-r--r--tests/ui/redundant_allocation.stderr2
-rw-r--r--tests/ui/same_item_push.rs8
-rw-r--r--tests/ui/self_assignment.rs67
-rw-r--r--tests/ui/self_assignment.stderr70
-rw-r--r--tests/ui/should_impl_trait/corner_cases.rs83
-rw-r--r--tests/ui/should_impl_trait/method_list_1.rs87
-rw-r--r--tests/ui/should_impl_trait/method_list_1.stderr143
-rw-r--r--tests/ui/should_impl_trait/method_list_2.rs88
-rw-r--r--tests/ui/should_impl_trait/method_list_2.stderr153
-rw-r--r--tests/ui/single_char_push_str.fixed15
-rw-r--r--tests/ui/single_char_push_str.rs15
-rw-r--r--tests/ui/single_char_push_str.stderr34
-rw-r--r--tests/ui/stable_sort_primitive.stderr14
-rw-r--r--tests/ui/suspicious_arithmetic_impl.rs52
-rw-r--r--tests/ui/suspicious_arithmetic_impl.stderr44
-rw-r--r--tests/ui/to_string_in_display.rs55
-rw-r--r--tests/ui/to_string_in_display.stderr10
-rw-r--r--tests/ui/transmute.rs24
-rw-r--r--tests/ui/transmute.stderr66
-rw-r--r--tests/ui/transmute_float_to_int.rs16
-rw-r--r--tests/ui/transmute_float_to_int.stderr12
-rw-r--r--tests/ui/unnecessary_lazy_eval.fixed117
-rw-r--r--tests/ui/unnecessary_lazy_eval.rs117
-rw-r--r--tests/ui/unnecessary_lazy_eval.stderr148
-rw-r--r--tests/ui/useless_conversion.fixed5
-rw-r--r--tests/ui/useless_conversion.rs5
-rw-r--r--tests/ui/useless_conversion.stderr8
-rw-r--r--tests/ui/vec.fixed7
-rw-r--r--tests/ui/vec.rs7
-rwxr-xr-xutil/dev7
110 files changed, 3004 insertions, 916 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e9ed54c848..5ce63c0a157 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1690,6 +1690,7 @@ Released 2018-09-13
 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
+[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
@@ -1699,6 +1700,7 @@ Released 2018-09-13
 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
+[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
 [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
@@ -1723,6 +1725,7 @@ Released 2018-09-13
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
+[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
@@ -1752,6 +1755,7 @@ Released 2018-09-13
 [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
+[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
diff --git a/Cargo.toml b/Cargo.toml
index 836897927b0..c7a3099b8ab 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,13 +31,13 @@ path = "src/driver.rs"
 # begin automatic update
 clippy_lints = { version = "0.0.212", path = "clippy_lints" }
 # end automatic update
-semver = "0.9"
+semver = "0.10"
 rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
 tempfile = { version = "3.1.0", optional = true }
 lazy_static = "1.0"
 
 [dev-dependencies]
-cargo_metadata = "0.9.1"
+cargo_metadata = "0.11.1"
 compiletest_rs = { version = "0.5.0", features = ["tmp"] }
 tester = "0.7"
 lazy_static = "1.0"
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index e959c1a6511..cc7d3a04f00 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -17,7 +17,7 @@ keywords = ["clippy", "lint", "plugin"]
 edition = "2018"
 
 [dependencies]
-cargo_metadata = "0.9.1"
+cargo_metadata = "0.11.1"
 if_chain = "1.0.0"
 itertools = "0.9"
 lazy_static = "1.0.2"
@@ -28,7 +28,7 @@ serde = { version = "1.0", features = ["derive"] }
 smallvec = { version = "1", features = ["union"] }
 toml = "0.5.3"
 unicode-normalization = "0.1"
-semver = "0.9.0"
+semver = "0.10.0"
 # NOTE: cargo requires serde feat in its url dep
 # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
 url = { version =  "2.1.0", features = ["serde"] }
diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs
index dab1e96e282..b3185b88840 100644
--- a/clippy_lints/src/assign_ops.rs
+++ b/clippy_lints/src/assign_ops.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq,
+    eq_expr_value, get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method,
 };
 use crate::utils::{higher, sugg};
 use if_chain::if_chain;
@@ -70,11 +70,11 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps {
                         return;
                     }
                     // lhs op= l op r
-                    if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
+                    if eq_expr_value(cx, lhs, l) {
                         lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r);
                     }
                     // lhs op= l commutative_op r
-                    if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
+                    if is_commutative(op.node) && eq_expr_value(cx, lhs, r) {
                         lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l);
                     }
                 }
@@ -161,14 +161,12 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps {
 
                     if visitor.counter == 1 {
                         // a = a op b
-                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
+                        if eq_expr_value(cx, assignee, l) {
                             lint(assignee, r);
                         }
                         // a = b commutative_op a
                         // Limited to primitive type as these ops are know to be commutative
-                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
-                            && cx.typeck_results().expr_ty(assignee).is_primitive_ty()
-                        {
+                        if eq_expr_value(cx, assignee, r) && cx.typeck_results().expr_ty(assignee).is_primitive_ty() {
                             match op.node {
                                 hir::BinOpKind::Add
                                 | hir::BinOpKind::Mul
@@ -253,7 +251,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-        if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, expr) {
+        if eq_expr_value(self.cx, self.assignee, expr) {
             self.counter += 1;
         }
 
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 76ccf2e4bb9..cfcc1b3c5f3 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -5,8 +5,8 @@ use crate::utils::{
     span_lint_and_sugg, span_lint_and_then, without_block_comments,
 };
 use if_chain::if_chain;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_errors::Applicability;
 use rustc_hir::{
     Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index 18529f2113e..280a2c7fe67 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -1,6 +1,6 @@
 use crate::utils::{
-    get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, span_lint_and_sugg,
-    span_lint_and_then, SpanlessEq,
+    eq_expr_value, get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt,
+    span_lint_and_sugg, span_lint_and_then,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
@@ -128,7 +128,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
             }
         }
         for (n, expr) in self.terminals.iter().enumerate() {
-            if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) {
+            if eq_expr_value(self.cx, e, expr) {
                 #[allow(clippy::cast_possible_truncation)]
                 return Ok(Bool::Term(n as u8));
             }
@@ -138,8 +138,8 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
                 if implements_ord(self.cx, e_lhs);
                 if let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind;
                 if negate(e_binop.node) == Some(expr_binop.node);
-                if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_lhs, expr_lhs);
-                if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_rhs, expr_rhs);
+                if eq_expr_value(self.cx, e_lhs, expr_lhs);
+                if eq_expr_value(self.cx, e_rhs, expr_rhs);
                 then {
                     #[allow(clippy::cast_possible_truncation)]
                     return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index 1f8bff8d71e..10a64769585 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -1,5 +1,5 @@
+use crate::utils::{eq_expr_value, SpanlessEq, SpanlessHash};
 use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then};
-use crate::utils::{SpanlessEq, SpanlessHash};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -197,8 +197,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
         h.finish()
     };
 
-    let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool =
-        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
+    let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { eq_expr_value(cx, lhs, rhs) };
 
     for (i, j) in search_same(conds, hash, eq) {
         span_lint_and_note(
@@ -222,7 +221,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
 
     let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool {
         // Do not spawn warning if `IFS_SAME_COND` already produced it.
-        if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) {
+        if eq_expr_value(cx, lhs, rhs) {
             return false;
         }
         SpanlessEq::new(cx).eq_expr(lhs, rhs)
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 6ce36fd2360..9555459e240 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -1,16 +1,22 @@
 use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
 use if_chain::if_chain;
 use itertools::Itertools;
-use rustc_ast::ast::{AttrKind, Attribute};
+use rustc_ast::ast::{Async, AttrKind, Attribute, FnRetTy, ItemKind};
 use rustc_ast::token::CommentKind;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::emitter::EmitterWriter;
+use rustc_errors::Handler;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
+use rustc_parse::maybe_new_parser_from_source_str;
+use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::{BytePos, MultiSpan, Span};
-use rustc_span::Pos;
+use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
+use rustc_span::{FileName, Pos};
+use std::io;
 use std::ops::Range;
 use url::Url;
 
@@ -431,10 +437,67 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     headers
 }
 
-static LEAVE_MAIN_PATTERNS: &[&str] = &["static", "fn main() {}", "extern crate", "async fn main() {"];
-
 fn check_code(cx: &LateContext<'_>, text: &str, span: Span) {
-    if text.contains("fn main() {") && !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) {
+    fn has_needless_main(code: &str) -> bool {
+        let filename = FileName::anon_source_code(code);
+
+        let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+        let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
+        let handler = Handler::with_emitter(false, None, box emitter);
+        let sess = ParseSess::with_span_handler(handler, sm);
+
+        let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) {
+            Ok(p) => p,
+            Err(errs) => {
+                for mut err in errs {
+                    err.cancel();
+                }
+                return false;
+            },
+        };
+
+        let mut relevant_main_found = false;
+        loop {
+            match parser.parse_item() {
+                Ok(Some(item)) => match &item.kind {
+                    // Tests with one of these items are ignored
+                    ItemKind::Static(..)
+                    | ItemKind::Const(..)
+                    | ItemKind::ExternCrate(..)
+                    | ItemKind::ForeignMod(..) => return false,
+                    // We found a main function ...
+                    ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => {
+                        let is_async = matches!(sig.header.asyncness, Async::Yes{..});
+                        let returns_nothing = match &sig.decl.output {
+                            FnRetTy::Default(..) => true,
+                            FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
+                            _ => false,
+                        };
+
+                        if returns_nothing && !is_async && !block.stmts.is_empty() {
+                            // This main function should be linted, but only if there are no other functions
+                            relevant_main_found = true;
+                        } else {
+                            // This main function should not be linted, we're done
+                            return false;
+                        }
+                    },
+                    // Another function was found; this case is ignored too
+                    ItemKind::Fn(..) => return false,
+                    _ => {},
+                },
+                Ok(None) => break,
+                Err(mut e) => {
+                    e.cancel();
+                    return false;
+                },
+            }
+        }
+
+        relevant_main_found
+    }
+
+    if has_needless_main(text) {
         span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
     }
 }
diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs
index bae7c4647d4..19f56195ec1 100644
--- a/clippy_lints/src/double_comparison.rs
+++ b/clippy_lints/src/double_comparison.rs
@@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
+use crate::utils::{eq_expr_value, snippet_with_applicability, span_lint_and_sugg};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for double comparisons that could be simplified to a single expression.
@@ -46,8 +46,7 @@ impl<'tcx> DoubleComparisons {
             },
             _ => return,
         };
-        let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
-        if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) {
+        if !(eq_expr_value(cx, &llhs, &rlhs) && eq_expr_value(cx, &lrhs, &rrhs)) {
             return;
         }
         macro_rules! lint_double_comparison {
diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs
index 1dfb2eaa579..8ece44878fe 100644
--- a/clippy_lints/src/duration_subsec.rs
+++ b/clippy_lints/src/duration_subsec.rs
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec {
                     cx,
                     DURATION_SUBSEC,
                     expr.span,
-                    &format!("Calling `{}()` is more concise than this calculation", suggested_fn),
+                    &format!("calling `{}()` is more concise than this calculation", suggested_fn),
                     "try",
                     format!(
                         "{}.{}()",
diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs
index 91214f277be..48caf48dbdb 100644
--- a/clippy_lints/src/enum_clike.rs
+++ b/clippy_lints/src/enum_clike.rs
@@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                             cx,
                             ENUM_CLIKE_UNPORTABLE_VARIANT,
                             var.span,
-                            "Clike enum variant discriminant is not portable to 32-bit targets",
+                            "C-like enum variant discriminant is not portable to 32-bit targets",
                         );
                     };
                 }
diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs
index cb0fd59a2d4..a9294a87f15 100644
--- a/clippy_lints/src/enum_variants.rs
+++ b/clippy_lints/src/enum_variants.rs
@@ -183,10 +183,10 @@ fn check_variant(
             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
         {
-            span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
+            span_lint(cx, lint, var.span, "variant name starts with the enum's name");
         }
         if partial_rmatch(item_name, &name) == item_name_chars {
-            span_lint(cx, lint, var.span, "Variant name ends with the enum's name");
+            span_lint(cx, lint, var.span, "variant name ends with the enum's name");
         }
     }
     let first = &def.variants[0].ident.name.as_str();
@@ -227,7 +227,7 @@ fn check_variant(
         cx,
         lint,
         span,
-        &format!("All variants have the same {}fix: `{}`", what, value),
+        &format!("all variants have the same {}fix: `{}`", what, value),
         None,
         &format!(
             "remove the {}fixes and use full paths to \
diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs
index 140cd21c34e..e16ec783fab 100644
--- a/clippy_lints/src/eq_op.rs
+++ b/clippy_lints/src/eq_op.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq,
+    eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind};
@@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
             if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) {
                 return;
             }
-            if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
+            if is_valid_operator(op) && eq_expr_value(cx, left, right) {
                 span_lint(
                     cx,
                     EQ_OP,
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index 93f6ec92ec7..1b02cee126d 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -2,7 +2,7 @@ use crate::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
-use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
+use crate::utils::{eq_expr_value, get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -363,8 +363,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
         if_chain! {
             if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
             if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
-            if are_exprs_equal(cx, lmul_lhs, lmul_rhs);
-            if are_exprs_equal(cx, rmul_lhs, rmul_rhs);
+            if eq_expr_value(cx, lmul_lhs, lmul_rhs);
+            if eq_expr_value(cx, rmul_lhs, rmul_rhs);
             then {
                 return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, "..")));
             }
@@ -502,8 +502,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
 fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
     if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
         match op {
-            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && are_exprs_equal(cx, left, test),
-            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && are_exprs_equal(cx, right, test),
+            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && eq_expr_value(cx, left, test),
+            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && eq_expr_value(cx, right, test),
             _ => false,
         }
     } else {
@@ -515,8 +515,8 @@ fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
 fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
     if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
         match op {
-            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && are_exprs_equal(cx, right, test),
-            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && are_exprs_equal(cx, left, test),
+            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && eq_expr_value(cx, right, test),
+            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && eq_expr_value(cx, left, test),
             _ => false,
         }
     } else {
@@ -524,10 +524,6 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
     }
 }
 
-fn are_exprs_equal(cx: &LateContext<'_>, expr1: &Expr<'_>, expr2: &Expr<'_>) -> bool {
-    SpanlessEq::new(cx).ignore_fn().eq_expr(expr1, expr2)
-}
-
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match constant_simple(cx, cx.typeck_results(), expr) {
@@ -546,12 +542,12 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// returns None.
 fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> {
     if let ExprKind::Unary(UnOp::UnNeg, expr1_negated) = &expr1.kind {
-        if are_exprs_equal(cx, expr1_negated, expr2) {
+        if eq_expr_value(cx, expr1_negated, expr2) {
             return Some((false, expr2));
         }
     }
     if let ExprKind::Unary(UnOp::UnNeg, expr2_negated) = &expr2.kind {
-        if are_exprs_equal(cx, expr1, expr2_negated) {
+        if eq_expr_value(cx, expr1, expr2_negated) {
             return Some((true, expr1));
         }
     }
@@ -614,7 +610,7 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>
                 args_a.len() == args_b.len() &&
                 (
                     ["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) ||
-                    method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1])
+                    method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
                 );
         }
     }
diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs
index 5b22df5fe49..28b20cdeac3 100644
--- a/clippy_lints/src/if_let_some_result.rs
+++ b/clippy_lints/src/if_let_some_result.rs
@@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet {
                     cx,
                     IF_LET_SOME_RESULT,
                     expr.span.with_hi(op.span.hi()),
-                    "Matching on `Some` with `ok()` is redundant",
-                    &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
+                    "matching on `Some` with `ok()` is redundant",
+                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
                     sugg,
                     applicability,
                 );
diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs
index c11e291f98e..b86d2e76656 100644
--- a/clippy_lints/src/if_not_else.rs
+++ b/clippy_lints/src/if_not_else.rs
@@ -60,7 +60,7 @@ impl EarlyLintPass for IfNotElse {
                             cx,
                             IF_NOT_ELSE,
                             item.span,
-                            "Unnecessary boolean `not` operation",
+                            "unnecessary boolean `not` operation",
                             None,
                             "remove the `!` and swap the blocks of the `if`/`else`",
                         );
@@ -70,7 +70,7 @@ impl EarlyLintPass for IfNotElse {
                             cx,
                             IF_NOT_ELSE,
                             item.span,
-                            "Unnecessary `!=` operation",
+                            "unnecessary `!=` operation",
                             None,
                             "change to `==` and swap the blocks of the `if`/`else`",
                         );
diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs
index 5f931a0adde..b57fe8dc426 100644
--- a/clippy_lints/src/implicit_saturating_sub.rs
+++ b/clippy_lints/src/implicit_saturating_sub.rs
@@ -158,9 +158,9 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) {
         cx,
         IMPLICIT_SATURATING_SUB,
         expr.span,
-        "Implicitly performing saturating subtraction",
+        "implicitly performing saturating subtraction",
         "try",
-        format!("{} = {}.saturating_sub({});", var_name, var_name, 1.to_string()),
+        format!("{} = {}.saturating_sub({});", var_name, var_name, '1'),
         Applicability::MachineApplicable,
     );
 }
diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs
index 9fb10c7f627..4e6bb604785 100644
--- a/clippy_lints/src/inherent_impl.rs
+++ b/clippy_lints/src/inherent_impl.rs
@@ -81,9 +81,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
                             cx,
                             MULTIPLE_INHERENT_IMPL,
                             *additional_span,
-                            "Multiple implementations of this structure",
+                            "multiple implementations of this structure",
                             |diag| {
-                                diag.span_note(*initial_span, "First implementation here");
+                                diag.span_note(*initial_span, "first implementation here");
                             },
                         )
                     })
diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs
index e91fb0c2f27..c629ee05ab9 100644
--- a/clippy_lints/src/int_plus_one.rs
+++ b/clippy_lints/src/int_plus_one.rs
@@ -152,7 +152,7 @@ impl IntPlusOne {
             cx,
             INT_PLUS_ONE,
             block.span,
-            "Unnecessary `>= y + 1` or `x - 1 >=`",
+            "unnecessary `>= y + 1` or `x - 1 >=`",
             "change it to",
             recommendation,
             Applicability::MachineApplicable, // snippet
@@ -163,8 +163,8 @@ impl IntPlusOne {
 impl EarlyLintPass for IntPlusOne {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
         if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind {
-            if let Some(ref rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
-                Self::emit_warning(cx, item, rec.clone());
+            if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
+                Self::emit_warning(cx, item, rec);
             }
         }
     }
diff --git a/clippy_lints/src/let_and_return.rs b/clippy_lints/src/let_and_return.rs
deleted file mode 100644
index fa560ffb980..00000000000
--- a/clippy_lints/src/let_and_return.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then};
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for `let`-bindings, which are subsequently
-    /// returned.
-    ///
-    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
-    /// more rusty.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// fn foo() -> String {
-    ///     let x = String::new();
-    ///     x
-    /// }
-    /// ```
-    /// instead, use
-    /// ```
-    /// fn foo() -> String {
-    ///     String::new()
-    /// }
-    /// ```
-    pub LET_AND_RETURN,
-    style,
-    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
-}
-
-declare_lint_pass!(LetReturn => [LET_AND_RETURN]);
-
-impl<'tcx> LateLintPass<'tcx> for LetReturn {
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        // we need both a let-binding stmt and an expr
-        if_chain! {
-            if let Some(retexpr) = block.expr;
-            if let Some(stmt) = block.stmts.iter().last();
-            if let StmtKind::Local(local) = &stmt.kind;
-            if local.ty.is_none();
-            if local.attrs.is_empty();
-            if let Some(initexpr) = &local.init;
-            if let PatKind::Binding(.., ident, _) = local.pat.kind;
-            if let ExprKind::Path(qpath) = &retexpr.kind;
-            if match_qpath(qpath, &[&*ident.name.as_str()]);
-            if !last_statement_borrows(cx, initexpr);
-            if !in_external_macro(cx.sess(), initexpr.span);
-            if !in_external_macro(cx.sess(), retexpr.span);
-            if !in_external_macro(cx.sess(), local.span);
-            if !in_macro(local.span);
-            then {
-                span_lint_and_then(
-                    cx,
-                    LET_AND_RETURN,
-                    retexpr.span,
-                    "returning the result of a `let` binding from a block",
-                    |err| {
-                        err.span_label(local.span, "unnecessary `let` binding");
-
-                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
-                            err.multipart_suggestion(
-                                "return the expression directly",
-                                vec![
-                                    (local.span, String::new()),
-                                    (retexpr.span, snippet),
-                                ],
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            err.span_help(initexpr.span, "this expression can be directly returned");
-                        }
-                    },
-                );
-            }
-        }
-    }
-}
-
-fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    let mut visitor = BorrowVisitor { cx, borrows: false };
-    walk_expr(&mut visitor, expr);
-    visitor.borrows
-}
-
-struct BorrowVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    borrows: bool,
-}
-
-impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.borrows {
-            return;
-        }
-
-        if let Some(def_id) = fn_def_id(self.cx, expr) {
-            self.borrows = self
-                .cx
-                .tcx
-                .fn_sig(def_id)
-                .output()
-                .skip_binder()
-                .walk()
-                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
-        }
-
-        walk_expr(self, expr);
-    }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index aa100263640..d45394ab8d2 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -218,7 +218,6 @@ mod large_const_arrays;
 mod large_enum_variant;
 mod large_stack_arrays;
 mod len_zero;
-mod let_and_return;
 mod let_if_seq;
 mod let_underscore;
 mod lifetimes;
@@ -285,6 +284,7 @@ mod reference;
 mod regex;
 mod repeat_once;
 mod returns;
+mod self_assignment;
 mod serde_api;
 mod shadow;
 mod single_component_path_imports;
@@ -296,6 +296,7 @@ mod swap;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod to_digit_is_some;
+mod to_string_in_display;
 mod trait_bounds;
 mod transmute;
 mod transmuting_null;
@@ -310,6 +311,7 @@ mod unnested_or_patterns;
 mod unsafe_removed_from_name;
 mod unused_io_amount;
 mod unused_self;
+mod unused_unit;
 mod unwrap;
 mod use_self;
 mod useless_conversion;
@@ -586,7 +588,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &large_stack_arrays::LARGE_STACK_ARRAYS,
         &len_zero::LEN_WITHOUT_IS_EMPTY,
         &len_zero::LEN_ZERO,
-        &let_and_return::LET_AND_RETURN,
         &let_if_seq::USELESS_LET_IF_SEQ,
         &let_underscore::LET_UNDERSCORE_LOCK,
         &let_underscore::LET_UNDERSCORE_MUST_USE,
@@ -677,6 +678,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::SEARCH_IS_SOME,
         &methods::SHOULD_IMPLEMENT_TRAIT,
         &methods::SINGLE_CHAR_PATTERN,
+        &methods::SINGLE_CHAR_PUSH_STR,
         &methods::SKIP_WHILE_NEXT,
         &methods::STRING_EXTEND_CHARS,
         &methods::SUSPICIOUS_MAP,
@@ -684,6 +686,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::UNINIT_ASSUMED_INIT,
         &methods::UNNECESSARY_FILTER_MAP,
         &methods::UNNECESSARY_FOLD,
+        &methods::UNNECESSARY_LAZY_EVALUATIONS,
         &methods::UNWRAP_USED,
         &methods::USELESS_ASREF,
         &methods::WRONG_PUB_SELF_CONVENTION,
@@ -769,8 +772,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &regex::INVALID_REGEX,
         &regex::TRIVIAL_REGEX,
         &repeat_once::REPEAT_ONCE,
+        &returns::LET_AND_RETURN,
         &returns::NEEDLESS_RETURN,
-        &returns::UNUSED_UNIT,
+        &self_assignment::SELF_ASSIGNMENT,
         &serde_api::SERDE_API_MISUSE,
         &shadow::SHADOW_REUSE,
         &shadow::SHADOW_SAME,
@@ -788,6 +792,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
         &temporary_assignment::TEMPORARY_ASSIGNMENT,
         &to_digit_is_some::TO_DIGIT_IS_SOME,
+        &to_string_in_display::TO_STRING_IN_DISPLAY,
         &trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
         &trait_bounds::TYPE_REPETITION_IN_BOUNDS,
         &transmute::CROSSPOINTER_TRANSMUTE,
@@ -840,6 +845,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
         &unused_io_amount::UNUSED_IO_AMOUNT,
         &unused_self::UNUSED_SELF,
+        &unused_unit::UNUSED_UNIT,
         &unwrap::PANICKING_UNWRAP,
         &unwrap::UNNECESSARY_UNWRAP,
         &use_self::USE_SELF,
@@ -930,11 +936,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
     let too_large_for_stack = conf.too_large_for_stack;
     store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
     store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
     store.register_late_pass(|| box strings::StringLitAsBytes);
     store.register_late_pass(|| box derive::Derive);
     store.register_late_pass(|| box types::CharLitAsU8);
-    store.register_late_pass(|| box vec::UselessVec);
     store.register_late_pass(|| box drop_bounds::DropBounds);
     store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
     store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
@@ -1017,6 +1023,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box reference::DerefAddrOf);
     store.register_early_pass(|| box reference::RefInDeref);
     store.register_early_pass(|| box double_parens::DoubleParens);
+    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
     store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
     store.register_early_pass(|| box if_not_else::IfNotElse);
     store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
@@ -1025,8 +1032,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box misc_early::MiscEarlyLints);
     store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
     store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_early_pass(|| box returns::Return);
-    store.register_late_pass(|| box let_and_return::LetReturn);
+    store.register_early_pass(|| box unused_unit::UnusedUnit);
+    store.register_late_pass(|| box returns::Return);
     store.register_early_pass(|| box collapsible_if::CollapsibleIf);
     store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
     store.register_early_pass(|| box precedence::Precedence);
@@ -1085,6 +1092,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
     store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
     store.register_late_pass(|| box repeat_once::RepeatOnce);
+    store.register_late_pass(|| box self_assignment::SelfAssignment);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1284,7 +1292,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
-        LintId::of(&let_and_return::LET_AND_RETURN),
         LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
         LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
         LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
@@ -1349,6 +1356,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::SEARCH_IS_SOME),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
         LintId::of(&methods::SINGLE_CHAR_PATTERN),
+        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
         LintId::of(&methods::SKIP_WHILE_NEXT),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::SUSPICIOUS_MAP),
@@ -1356,6 +1364,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::UNINIT_ASSUMED_INIT),
         LintId::of(&methods::UNNECESSARY_FILTER_MAP),
         LintId::of(&methods::UNNECESSARY_FOLD),
+        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
         LintId::of(&methods::USELESS_ASREF),
         LintId::of(&methods::WRONG_SELF_CONVENTION),
         LintId::of(&methods::ZST_OFFSET),
@@ -1413,8 +1422,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&regex::INVALID_REGEX),
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&repeat_once::REPEAT_ONCE),
+        LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
-        LintId::of(&returns::UNUSED_UNIT),
+        LintId::of(&self_assignment::SELF_ASSIGNMENT),
         LintId::of(&serde_api::SERDE_API_MISUSE),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
@@ -1427,6 +1437,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
         LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
+        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
         LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
         LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
         LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR),
@@ -1460,6 +1471,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
         LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
+        LintId::of(&unused_unit::UNUSED_UNIT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
@@ -1500,7 +1512,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&inherent_to_string::INHERENT_TO_STRING),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
-        LintId::of(&let_and_return::LET_AND_RETURN),
         LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
         LintId::of(&loops::EMPTY_LOOP),
         LintId::of(&loops::FOR_KV_MAP),
@@ -1532,8 +1543,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::OPTION_MAP_OR_NONE),
         LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
+        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::UNNECESSARY_FOLD),
+        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
         LintId::of(&methods::WRONG_SELF_CONVENTION),
         LintId::of(&misc::TOPLEVEL_REF_ARG),
         LintId::of(&misc::ZERO_PTR),
@@ -1554,8 +1567,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
         LintId::of(&regex::TRIVIAL_REGEX),
+        LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
-        LintId::of(&returns::UNUSED_UNIT),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
@@ -1564,6 +1577,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::FN_TO_NUMERIC_CAST),
         LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
         LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
+        LintId::of(&unused_unit::UNUSED_UNIT),
         LintId::of(&write::PRINTLN_EMPTY_STRING),
         LintId::of(&write::PRINT_LITERAL),
         LintId::of(&write::PRINT_WITH_NEWLINE),
@@ -1704,10 +1718,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ptr::MUT_FROM_REF),
         LintId::of(&ranges::REVERSED_EMPTY_RANGES),
         LintId::of(&regex::INVALID_REGEX),
+        LintId::of(&self_assignment::SELF_ASSIGNMENT),
         LintId::of(&serde_api::SERDE_API_MISUSE),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(&swap::ALMOST_SWAPPED),
+        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
         LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
         LintId::of(&transmute::WRONG_TRANSMUTE),
         LintId::of(&transmuting_null::TRANSMUTING_NULL),
diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs
index 8ffcd417d1d..c95e43a9430 100644
--- a/clippy_lints/src/loops.rs
+++ b/clippy_lints/src/loops.rs
@@ -1141,11 +1141,31 @@ fn detect_same_item_push<'tcx>(
     if same_item_push_visitor.should_lint {
         if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push {
             // Make sure that the push does not involve possibly mutating values
-            if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
-                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 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
+                                ),
+                            )
+                        }
+                    }
+                } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
                     span_lint_and_help(
                         cx,
                         SAME_ITEM_PUSH,
diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs
index 641e6a17043..1cd5b201292 100644
--- a/clippy_lints/src/map_clone.rs
+++ b/clippy_lints/src/map_clone.rs
@@ -111,8 +111,8 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
         cx,
         MAP_CLONE,
         root.trim_start(receiver).unwrap(),
-        "You are needlessly cloning iterator elements",
-        "Remove the `map` call",
+        "you are needlessly cloning iterator elements",
+        "remove the `map` call",
         String::new(),
         Applicability::MachineApplicable,
     )
@@ -125,8 +125,8 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
             cx,
             MAP_CLONE,
             replace,
-            "You are using an explicit closure for copying elements",
-            "Consider calling the dedicated `copied` method",
+            "you are using an explicit closure for copying elements",
+            "consider calling the dedicated `copied` method",
             format!(
                 "{}.copied()",
                 snippet_with_applicability(cx, root, "..", &mut applicability)
@@ -138,8 +138,8 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
             cx,
             MAP_CLONE,
             replace,
-            "You are using an explicit closure for cloning elements",
-            "Consider calling the dedicated `cloned` method",
+            "you are using an explicit closure for cloning elements",
+            "consider calling the dedicated `cloned` method",
             format!(
                 "{}.cloned()",
                 snippet_with_applicability(cx, root, "..", &mut applicability)
diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs
index faa20687ef6..57966452253 100644
--- a/clippy_lints/src/match_on_vec_items.rs
+++ b/clippy_lints/src/match_on_vec_items.rs
@@ -1,5 +1,5 @@
-use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
 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;
 use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 2265a188855..2498c48f067 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3,6 +3,7 @@ mod inefficient_to_string;
 mod manual_saturating_arithmetic;
 mod option_map_unwrap_or;
 mod unnecessary_filter_map;
+mod unnecessary_lazy_eval;
 
 use std::borrow::Cow;
 use std::fmt;
@@ -799,7 +800,7 @@ declare_clippy_lint! {
     ///     call_some_ffi_func(c_str);
     /// }
     /// ```
-    /// Here `c_str` point to a freed address. The correct use would be:
+    /// Here `c_str` points to a freed address. The correct use would be:
     /// ```rust
     /// # use std::ffi::CString;
     /// # fn call_some_ffi_func(_: *const i8) {}
@@ -1306,6 +1307,65 @@ declare_clippy_lint! {
     "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Warns when using push_str with a single-character string literal,
+    /// and push with a char would work fine.
+    ///
+    /// **Why is this bad?** It's less clear that we are pushing a single character
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```
+    /// let mut string = String::new();
+    /// string.push_str("R");
+    /// ```
+    /// Could be written as
+    /// ```
+    /// let mut string = String::new();
+    /// string.push('R');
+    /// ```
+    pub SINGLE_CHAR_PUSH_STR,
+    style,
+    "`push_str()` used with a single-character string literal as parameter"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary
+    /// lazily evaluated closures on `Option` and `Result`.
+    ///
+    /// This lint suggests changing the following functions, when eager evaluation results in
+    /// simpler code:
+    ///  - `unwrap_or_else` to `unwrap_or`
+    ///  - `and_then` to `and`
+    ///  - `or_else` to `or`
+    ///  - `get_or_insert_with` to `get_or_insert`
+    ///  - `ok_or_else` to `ok_or`
+    ///
+    /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases.
+    ///
+    /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have
+    /// side effects. Eagerly evaluating them can change the semantics of the program.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // example code where clippy issues a warning
+    /// let opt: Option<u32> = None;
+    ///
+    /// opt.unwrap_or_else(|| 42);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let opt: Option<u32> = None;
+    ///
+    /// opt.unwrap_or(42);
+    /// ```
+    pub UNNECESSARY_LAZY_EVALUATIONS,
+    style,
+    "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
+}
+
 declare_lint_pass!(Methods => [
     UNWRAP_USED,
     EXPECT_USED,
@@ -1327,6 +1387,7 @@ declare_lint_pass!(Methods => [
     INEFFICIENT_TO_STRING,
     NEW_RET_NO_SELF,
     SINGLE_CHAR_PATTERN,
+    SINGLE_CHAR_PUSH_STR,
     SEARCH_IS_SOME,
     TEMPORARY_CSTRING_AS_PTR,
     FILTER_NEXT,
@@ -1354,6 +1415,7 @@ declare_lint_pass!(Methods => [
     ZST_OFFSET,
     FILETYPE_IS_FILE,
     OPTION_AS_REF_DEREF,
+    UNNECESSARY_LAZY_EVALUATIONS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -1374,13 +1436,19 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
             ["expect", ..] => lint_expect(cx, expr, arg_lists[0]),
             ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
-            ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]),
+            ["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");
+                }
+            },
             ["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]);
             },
             ["or_else", ..] => {
+                unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
                 bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
             },
             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
@@ -1424,6 +1492,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"),
             _ => {},
         }
 
@@ -1441,6 +1512,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     inefficient_to_string::lint(cx, expr, &args[0], self_ty);
                 }
 
+                if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+                    if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
+                        lint_single_char_push_string(cx, expr, args);
+                    }
+                }
+
                 match self_ty.kind {
                     ty::Ref(_, ty, _) if ty.kind == ty::Str => {
                         for &(method, pos) in &PATTERN_METHODS {
@@ -1470,6 +1547,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         }
     }
 
+    #[allow(clippy::too_many_lines)]
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         if in_external_macro(cx.sess(), impl_item.span) {
             return;
@@ -1495,16 +1573,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
             then {
                 if cx.access_levels.is_exported(impl_item.hir_id) {
-                // check missing trait implementations
-                    for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS {
-                        if name == method_name &&
-                            sig.decl.inputs.len() == n_args &&
-                            out_type.matches(cx, &sig.decl.output) &&
-                            self_kind.matches(cx, self_ty, first_arg_ty) &&
-                            fn_header_equals(*fn_header, sig.header) {
-                            span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
-                                "defining a method called `{}` on this type; consider implementing \
-                                the `{}` trait or choosing a less ambiguous name", name, trait_name));
+                    // check missing trait implementations
+                    for method_config in &TRAIT_METHODS {
+                        if name == method_config.method_name &&
+                            sig.decl.inputs.len() == method_config.param_count &&
+                            method_config.output_type.matches(cx, &sig.decl.output) &&
+                            method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
+                            fn_header_equals(method_config.fn_header, sig.header) &&
+                            method_config.lifetime_param_cond(&impl_item)
+                        {
+                            span_lint_and_help(
+                                cx,
+                                SHOULD_IMPLEMENT_TRAIT,
+                                impl_item.span,
+                                &format!(
+                                    "method `{}` can be confused for the standard trait method `{}::{}`",
+                                    method_config.method_name,
+                                    method_config.trait_name,
+                                    method_config.method_name
+                                ),
+                                None,
+                                &format!(
+                                    "consider implementing the trait `{}` or choosing a less ambiguous method name",
+                                    method_config.trait_name
+                                )
+                            );
                         }
                     }
                 }
@@ -2280,7 +2373,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
                     cx,
                     ITER_NEXT_SLICE,
                     expr.span,
-                    "Using `.iter().next()` on a Slice without end index.",
+                    "using `.iter().next()` on a Slice without end index",
                     "try calling",
                     format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
                     applicability,
@@ -2299,7 +2392,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
             cx,
             ITER_NEXT_SLICE,
             expr.span,
-            "Using `.iter().next()` on an array",
+            "using `.iter().next()` on an array",
             "try calling",
             format!(
                 "{}.get(0)",
@@ -2618,12 +2711,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
 }
 
 /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
+/// Return true if lint triggered
 fn lint_map_unwrap_or_else<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
     map_args: &'tcx [hir::Expr<'_>],
     unwrap_args: &'tcx [hir::Expr<'_>],
-) {
+) -> bool {
     // lint if the caller of `map()` is an `Option`
     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type));
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type));
@@ -2635,10 +2729,10 @@ fn lint_map_unwrap_or_else<'tcx>(
         let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
-                return;
+                return false;
             }
         } else {
-            return;
+            return false;
         }
 
         // lint message
@@ -2668,10 +2762,14 @@ fn lint_map_unwrap_or_else<'tcx>(
                     map_snippet, unwrap_snippet,
                 ),
             );
+            return true;
         } else if same_span && multiline {
             span_lint(cx, MAP_UNWRAP_OR, expr.span, msg);
-        };
+            return true;
+        }
     }
+
+    false
 }
 
 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
@@ -3124,15 +3222,18 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx
     }
 }
 
-/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
+fn get_hint_if_single_char_arg(
+    cx: &LateContext<'_>,
+    arg: &hir::Expr<'_>,
+    applicability: &mut Applicability,
+) -> Option<String> {
     if_chain! {
         if let hir::ExprKind::Lit(lit) = &arg.kind;
         if let ast::LitKind::Str(r, style) = lit.node;
-        if r.as_str().len() == 1;
+        let string = r.as_str();
+        if string.len() == 1;
         then {
-            let mut applicability = Applicability::MachineApplicable;
-            let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
+            let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
             let ch = if let ast::StrStyle::Raw(nhash) = style {
                 let nhash = nhash as usize;
                 // for raw string: r##"a"##
@@ -3142,19 +3243,47 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr
                 &snip[1..(snip.len() - 1)]
             };
             let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
-            span_lint_and_sugg(
-                cx,
-                SINGLE_CHAR_PATTERN,
-                arg.span,
-                "single-character string constant used as pattern",
-                "try using a `char` instead",
-                hint,
-                applicability,
-            );
+            Some(hint)
+        } else {
+            None
         }
     }
 }
 
+/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
+fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_PATTERN,
+            arg.span,
+            "single-character string constant used as pattern",
+            "try using a `char` instead",
+            hint,
+            applicability,
+        );
+    }
+}
+
+/// lint for length-1 `str`s as argument for `push_str`
+fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+        let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
+        let sugg = format!("{}.push({})", base_string_snippet, extension_string);
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_PUSH_STR,
+            expr.span,
+            "calling `push_str()` using a single-character string literal",
+            "consider using `push` with a character literal",
+            sugg,
+            applicability,
+        );
+    }
+}
+
 /// Checks for the `USELESS_ASREF` lint.
 fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
@@ -3403,38 +3532,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
     abi: rustc_target::spec::abi::Abi::Rust,
 };
 
+struct ShouldImplTraitCase {
+    trait_name: &'static str,
+    method_name: &'static str,
+    param_count: usize,
+    fn_header: hir::FnHeader,
+    // implicit self kind expected (none, self, &self, ...)
+    self_kind: SelfKind,
+    // checks against the output type
+    output_type: OutType,
+    // certain methods with explicit lifetimes can't implement the equivalent trait method
+    lint_explicit_lifetime: bool,
+}
+impl ShouldImplTraitCase {
+    const fn new(
+        trait_name: &'static str,
+        method_name: &'static str,
+        param_count: usize,
+        fn_header: hir::FnHeader,
+        self_kind: SelfKind,
+        output_type: OutType,
+        lint_explicit_lifetime: bool,
+    ) -> ShouldImplTraitCase {
+        ShouldImplTraitCase {
+            trait_name,
+            method_name,
+            param_count,
+            fn_header,
+            self_kind,
+            output_type,
+            lint_explicit_lifetime,
+        }
+    }
+
+    fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
+        self.lint_explicit_lifetime
+            || !impl_item.generics.params.iter().any(|p| {
+                matches!(
+                    p.kind,
+                    hir::GenericParamKind::Lifetime {
+                        kind: hir::LifetimeParamKind::Explicit
+                    }
+                )
+            })
+    }
+}
+
 #[rustfmt::skip]
-const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [
-    ("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"),
-    ("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
-    ("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
-    ("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
-    ("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
-    ("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
-    ("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
-    ("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
-    ("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
-    ("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
-    ("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"),
-    ("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
-    ("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
-    ("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"),
-    ("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
-    ("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
-    ("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
-    ("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"),
-    ("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
-    ("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
-    ("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
-    ("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
-    ("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"),
-    ("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"),
-    ("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
-    ("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"),
-    ("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"),
-    ("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"),
-    ("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"),
-    ("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"),
+const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
+    ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    // FIXME: default doesn't work
+    ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
+    ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
+    ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 ];
 
 #[rustfmt::skip]
diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
new file mode 100644
index 00000000000..31517659c34
--- /dev/null
+++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -0,0 +1,111 @@
+use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg};
+use if_chain::if_chain;
+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));
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type));
+
+    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;
+
+            if can_simplify(ex, params, allow_variant_calls) {
+                let msg = if is_option {
+                    "unnecessary closure used to substitute value for `Option::None`"
+                } else {
+                    "unnecessary closure used to substitute value for `Result::Err`"
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    UNNECESSARY_LAZY_EVALUATIONS,
+                    expr.span,
+                    msg,
+                    &format!("Use `{}` instead", simplify_using),
+                    format!(
+                        "{0}.{1}({2})",
+                        snippet(cx, args[0].span, ".."),
+                        simplify_using,
+                        snippet(cx, ex.span, ".."),
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 482a563572d..06f367a8b77 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -433,8 +433,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             return;
         }
         let binding = match expr.kind {
-            ExprKind::Path(hir::QPath::LangItem(..)) => None,
-            ExprKind::Path(ref qpath) => {
+            ExprKind::Path(ref qpath) if !matches!(qpath, hir::QPath::LangItem(..)) => {
                 let binding = last_path_segment(qpath).ident.as_str();
                 if binding.starts_with('_') &&
                     !binding.starts_with("__") &&
diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs
index b8dc5081632..c506440ed79 100644
--- a/clippy_lints/src/mut_reference.rs
+++ b/clippy_lints/src/mut_reference.rs
@@ -9,8 +9,8 @@ declare_clippy_lint! {
     /// **What it does:** Detects passing a mutable reference to a function that only
     /// requires an immutable reference.
     ///
-    /// **Why is this bad?** The immutable reference rules out all other references
-    /// to the value. Also the code misleads about the intent of the call site.
+    /// **Why is this bad?** The mutable reference rules out all other references to
+    /// the value. Also the code misleads about the intent of the call site.
     ///
     /// **Known problems:** None.
     ///
@@ -39,6 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                         arguments,
                         cx.typeck_results().expr_ty(fn_expr),
                         &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
+                        "function",
                     );
                 }
             },
@@ -46,14 +47,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, &path.ident.as_str())
+                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
             },
             _ => (),
         }
     }
 }
 
-fn check_arguments<'tcx>(cx: &LateContext<'tcx>, arguments: &[Expr<'_>], type_definition: Ty<'tcx>, name: &str) {
+fn check_arguments<'tcx>(
+    cx: &LateContext<'tcx>,
+    arguments: &[Expr<'_>],
+    type_definition: Ty<'tcx>,
+    name: &str,
+    fn_kind: &str,
+) {
     match type_definition.kind {
         ty::FnDef(..) | ty::FnPtr(_) => {
             let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
@@ -68,7 +75,7 @@ fn check_arguments<'tcx>(cx: &LateContext<'tcx>, arguments: &[Expr<'_>], type_de
                                 cx,
                                 UNNECESSARY_MUT_PASSED,
                                 argument.span,
-                                &format!("The function/method `{}` doesn't need a mutable reference", name),
+                                &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name),
                             );
                         }
                     },
diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs
index 568898aa5c9..21efee71269 100644
--- a/clippy_lints/src/mutex_atomic.rs
+++ b/clippy_lints/src/mutex_atomic.rs
@@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex {
                 let mutex_param = subst.type_at(0);
                 if let Some(atomic_name) = get_atomic_name(mutex_param) {
                     let msg = format!(
-                        "Consider using an `{}` instead of a `Mutex` here. If you just want the locking \
-                         behavior and not the internal type, consider using `Mutex<()>`.",
+                        "consider using an `{}` instead of a `Mutex` here; if you just want the locking \
+                         behavior and not the internal type, consider using `Mutex<()>`",
                         atomic_name
                     );
                     match mutex_param.kind {
diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs
index 4797771e7bd..c9d18c3cb72 100644
--- a/clippy_lints/src/precedence.rs
+++ b/clippy_lints/src/precedence.rs
@@ -1,4 +1,5 @@
 use crate::utils::{snippet_with_applicability, span_lint_and_sugg};
+use if_chain::if_chain;
 use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -102,36 +103,36 @@ impl EarlyLintPass for Precedence {
             }
         }
 
-        if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind {
-            if let ExprKind::MethodCall(ref path_segment, ref args, _) = rhs.kind {
+        if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind {
+            let mut arg = operand;
+
+            let mut all_odd = true;
+            while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
                 let path_segment_str = path_segment.ident.name.as_str();
-                if let Some(slf) = args.first() {
-                    if let ExprKind::Lit(ref lit) = slf.kind {
-                        match lit.kind {
-                            LitKind::Int(..) | LitKind::Float(..) => {
-                                if ALLOWED_ODD_FUNCTIONS
-                                    .iter()
-                                    .any(|odd_function| **odd_function == *path_segment_str)
-                                {
-                                    return;
-                                }
-                                let mut applicability = Applicability::MachineApplicable;
-                                span_lint_and_sugg(
-                                    cx,
-                                    PRECEDENCE,
-                                    expr.span,
-                                    "unary minus has lower precedence than method call",
-                                    "consider adding parentheses to clarify your intent",
-                                    format!(
-                                        "-({})",
-                                        snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
-                                    ),
-                                    applicability,
-                                );
-                            },
-                            _ => (),
-                        }
-                    }
+                all_odd &= ALLOWED_ODD_FUNCTIONS
+                    .iter()
+                    .any(|odd_function| **odd_function == *path_segment_str);
+                arg = args.first().expect("A method always has a receiver.");
+            }
+
+            if_chain! {
+                if !all_odd;
+                if let ExprKind::Lit(lit) = &arg.kind;
+                if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
+                then {
+                    let mut applicability = Applicability::MachineApplicable;
+                    span_lint_and_sugg(
+                        cx,
+                        PRECEDENCE,
+                        expr.span,
+                        "unary minus has lower precedence than method call",
+                        "consider adding parentheses to clarify your intent",
+                        format!(
+                            "-({})",
+                            snippet_with_applicability(cx, operand.span, "..", &mut applicability)
+                        ),
+                        applicability,
+                    );
                 }
             }
         }
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 460d631fab0..7dafb1555dc 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -36,14 +36,27 @@ declare_clippy_lint! {
     /// argument may also fail to compile if you change the argument. Applying
     /// this lint on them will fix the problem, but they may be in other crates.
     ///
+    /// One notable example of a function that may cause issues, and which cannot
+    /// easily be changed due to being in the standard library is `Vec::contains`.
+    /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
+    /// it will compile, but if a `&[T]` is passed then it will not compile.
+    ///
+    /// ```ignore
+    /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
+    ///     let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
+    ///
+    ///     vec_of_vecs.contains(v)
+    /// }
+    /// ```
+    ///
     /// Also there may be `fn(&Vec)`-typed references pointing to your function.
     /// If you have them, you will get a compiler error after applying this lint's
     /// suggestions. You then have the choice to undo your changes or change the
     /// type of the reference.
     ///
     /// Note that if the function is part of your public interface, there may be
-    /// other crates referencing it you may not be aware. Carefully deprecate the
-    /// function before applying the lint suggestions in this case.
+    /// other crates referencing it, of which you may not be aware. Carefully
+    /// deprecate the function before applying the lint suggestions in this case.
     ///
     /// **Example:**
     /// ```ignore
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index fb12c565afd..dbc676ae224 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -7,8 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 use crate::utils::sugg::Sugg;
 use crate::utils::{
-    higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability,
-    span_lint_and_sugg, SpanlessEq,
+    eq_expr_value, higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability,
+    span_lint_and_sugg,
 };
 
 declare_clippy_lint! {
@@ -65,7 +65,7 @@ impl QuestionMark {
                         if let ExprKind::Block(block, None) = &else_.kind;
                         if block.stmts.is_empty();
                         if let Some(block_expr) = &block.expr;
-                        if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
+                        if eq_expr_value(cx, subject, block_expr);
                         then {
                             replacement = Some(format!("Some({}?)", receiver_str));
                         }
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 8ed20995a70..3c5541e64b4 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -1,60 +1,67 @@
 use if_chain::if_chain;
-use rustc_ast::ast;
-use rustc_ast::visit::FnKind;
+use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::BytePos;
 
-use crate::utils::{snippet_opt, span_lint_and_sugg, span_lint_and_then};
+use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then};
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for return statements at the end of a block.
+    /// **What it does:** Checks for `let`-bindings, which are subsequently
+    /// returned.
     ///
-    /// **Why is this bad?** Removing the `return` and semicolon will make the code
+    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
     /// more rusty.
     ///
-    /// **Known problems:** If the computation returning the value borrows a local
-    /// variable, removing the `return` may run afoul of the borrow checker.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
-    /// fn foo(x: usize) -> usize {
-    ///     return x;
+    /// fn foo() -> String {
+    ///     let x = String::new();
+    ///     x
     /// }
     /// ```
-    /// simplify to
-    /// ```rust
-    /// fn foo(x: usize) -> usize {
-    ///     x
+    /// instead, use
+    /// ```
+    /// fn foo() -> String {
+    ///     String::new()
     /// }
     /// ```
-    pub NEEDLESS_RETURN,
+    pub LET_AND_RETURN,
     style,
-    "using a return statement like `return expr;` where an expression would suffice"
+    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
+    /// **What it does:** Checks for return statements at the end of a block.
     ///
-    /// **Why is this bad?** Such expressions add no value, but can make the code
-    /// less readable. Depending on formatting they can make a `break` or `return`
-    /// statement look like a function call.
+    /// **Why is this bad?** Removing the `return` and semicolon will make the code
+    /// more rusty.
     ///
-    /// **Known problems:** The lint currently misses unit return types in types,
-    /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
-    /// fn return_unit() -> () {
-    ///     ()
+    /// fn foo(x: usize) -> usize {
+    ///     return x;
     /// }
     /// ```
-    pub UNUSED_UNIT,
+    /// simplify to
+    /// ```rust
+    /// fn foo(x: usize) -> usize {
+    ///     x
+    /// }
+    /// ```
+    pub NEEDLESS_RETURN,
     style,
-    "needless unit expression"
+    "using a return statement like `return expr;` where an expression would suffice"
 }
 
 #[derive(PartialEq, Eq, Copy, Clone)]
@@ -63,221 +70,217 @@ enum RetReplacement {
     Block,
 }
 
-declare_lint_pass!(Return => [NEEDLESS_RETURN, UNUSED_UNIT]);
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
 
-impl Return {
-    // Check the final stmt or expr in a block for unnecessary return.
-    fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        if let Some(stmt) = block.stmts.last() {
-            match stmt.kind {
-                ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
-                    self.check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
-                },
-                _ => (),
+impl<'tcx> LateLintPass<'tcx> for Return {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+        // we need both a let-binding stmt and an expr
+        if_chain! {
+            if let Some(retexpr) = block.expr;
+            if let Some(stmt) = block.stmts.iter().last();
+            if let StmtKind::Local(local) = &stmt.kind;
+            if local.ty.is_none();
+            if local.attrs.is_empty();
+            if let Some(initexpr) = &local.init;
+            if let PatKind::Binding(.., ident, _) = local.pat.kind;
+            if let ExprKind::Path(qpath) = &retexpr.kind;
+            if match_qpath(qpath, &[&*ident.name.as_str()]);
+            if !last_statement_borrows(cx, initexpr);
+            if !in_external_macro(cx.sess(), initexpr.span);
+            if !in_external_macro(cx.sess(), retexpr.span);
+            if !in_external_macro(cx.sess(), local.span);
+            if !in_macro(local.span);
+            then {
+                span_lint_and_then(
+                    cx,
+                    LET_AND_RETURN,
+                    retexpr.span,
+                    "returning the result of a `let` binding from a block",
+                    |err| {
+                        err.span_label(local.span, "unnecessary `let` binding");
+
+                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
+                            err.multipart_suggestion(
+                                "return the expression directly",
+                                vec![
+                                    (local.span, String::new()),
+                                    (retexpr.span, snippet),
+                                ],
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.span_help(initexpr.span, "this expression can be directly returned");
+                        }
+                    },
+                );
             }
         }
     }
 
-    // Check the final expression in a block if it's a return.
-    fn check_final_expr(
+    fn check_fn(
         &mut self,
-        cx: &EarlyContext<'_>,
-        expr: &ast::Expr,
-        span: Option<Span>,
-        replacement: RetReplacement,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        _: Span,
+        _: HirId,
     ) {
-        match expr.kind {
-            // simple return is always "bad"
-            ast::ExprKind::Ret(ref inner) => {
-                // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
-                if !expr.attrs.iter().any(attr_is_cfg) {
-                    Self::emit_return_lint(
-                        cx,
-                        span.expect("`else return` is not possible"),
-                        inner.as_ref().map(|i| i.span),
-                        replacement,
-                    );
-                }
-            },
-            // a whole block? check it!
-            ast::ExprKind::Block(ref block, _) => {
-                self.check_block_return(cx, block);
-            },
-            // an if/if let expr, check both exprs
-            // note, if without else is going to be a type checking error anyways
-            // (except for unit type functions) so we don't match it
-            ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
-                self.check_block_return(cx, ifblock);
-                self.check_final_expr(cx, elsexpr, None, RetReplacement::Empty);
-            },
-            // a match expr, check all arms
-            ast::ExprKind::Match(_, ref arms) => {
-                for arm in arms {
-                    self.check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
+        match kind {
+            FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty),
+            FnKind::ItemFn(..) | FnKind::Method(..) => {
+                if let ExprKind::Block(ref block, _) = body.value.kind {
+                    check_block_return(cx, block);
                 }
             },
-            _ => (),
         }
     }
+}
 
-    fn emit_return_lint(cx: &EarlyContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
-        match inner_span {
-            Some(inner_span) => {
-                if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() {
-                    return;
-                }
+fn attr_is_cfg(attr: &Attribute) -> bool {
+    attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
+}
 
-                span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
-                    if let Some(snippet) = snippet_opt(cx, inner_span) {
-                        diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
-                    }
-                })
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+    if let Some(expr) = block.expr {
+        check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
+    } else if let Some(stmt) = block.stmts.iter().last() {
+        match stmt.kind {
+            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+                check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
             },
-            None => match replacement {
-                RetReplacement::Empty => {
-                    span_lint_and_sugg(
-                        cx,
-                        NEEDLESS_RETURN,
-                        ret_span,
-                        "unneeded `return` statement",
-                        "remove `return`",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                },
-                RetReplacement::Block => {
-                    span_lint_and_sugg(
+            _ => (),
+        }
+    }
+}
+
+fn check_final_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    span: Option<Span>,
+    replacement: RetReplacement,
+) {
+    match expr.kind {
+        // simple return is always "bad"
+        ExprKind::Ret(ref inner) => {
+            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
+            if !expr.attrs.iter().any(attr_is_cfg) {
+                let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
+                if !borrows {
+                    emit_return_lint(
                         cx,
-                        NEEDLESS_RETURN,
-                        ret_span,
-                        "unneeded `return` statement",
-                        "replace `return` with an empty block",
-                        "{}".to_string(),
-                        Applicability::MachineApplicable,
+                        span.expect("`else return` is not possible"),
+                        inner.as_ref().map(|i| i.span),
+                        replacement,
                     );
-                },
+                }
+            }
+        },
+        // a whole block? check it!
+        ExprKind::Block(ref block, _) => {
+            check_block_return(cx, block);
+        },
+        // a match expr, check all arms
+        // an if/if let expr, check both exprs
+        // note, if without else is going to be a type checking error anyways
+        // (except for unit type functions) so we don't match it
+        ExprKind::Match(_, ref arms, source) => match source {
+            MatchSource::Normal => {
+                for arm in arms.iter() {
+                    check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
+                }
             },
-        }
+            MatchSource::IfDesugar {
+                contains_else_clause: true,
+            }
+            | MatchSource::IfLetDesugar {
+                contains_else_clause: true,
+            } => {
+                if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
+                    check_block_return(cx, ifblock);
+                }
+                check_final_expr(cx, arms[1].body, None, RetReplacement::Empty);
+            },
+            _ => (),
+        },
+        _ => (),
     }
 }
 
-impl EarlyLintPass for Return {
-    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
-        match kind {
-            FnKind::Fn(.., Some(block)) => self.check_block_return(cx, block),
-            FnKind::Closure(_, body) => self.check_final_expr(cx, body, Some(body.span), RetReplacement::Empty),
-            FnKind::Fn(.., None) => {},
-        }
-        if_chain! {
-            if let ast::FnRetTy::Ty(ref ty) = kind.decl().output;
-            if let ast::TyKind::Tup(ref vals) = ty.kind;
-            if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
-            then {
-                lint_unneeded_unit_return(cx, ty, span);
+fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
+    match inner_span {
+        Some(inner_span) => {
+            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
+                return;
             }
-        }
-    }
 
-    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        if_chain! {
-            if let Some(ref stmt) = block.stmts.last();
-            if let ast::StmtKind::Expr(ref expr) = stmt.kind;
-            if is_unit_expr(expr) && !stmt.span.from_expansion();
-            then {
-                let sp = expr.span;
+            span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
+                if let Some(snippet) = snippet_opt(cx, inner_span) {
+                    diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
+                }
+            })
+        },
+        None => match replacement {
+            RetReplacement::Empty => {
                 span_lint_and_sugg(
                     cx,
-                    UNUSED_UNIT,
-                    sp,
-                    "unneeded unit expression",
-                    "remove the final `()`",
+                    NEEDLESS_RETURN,
+                    ret_span,
+                    "unneeded `return` statement",
+                    "remove `return`",
                     String::new(),
                     Applicability::MachineApplicable,
                 );
-            }
-        }
-    }
-
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        match e.kind {
-            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
-                if is_unit_expr(expr) && !expr.span.from_expansion() {
-                    span_lint_and_sugg(
-                        cx,
-                        UNUSED_UNIT,
-                        expr.span,
-                        "unneeded `()`",
-                        "remove the `()`",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                }
             },
-            _ => (),
-        }
-    }
-
-    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
-        let segments = &poly.trait_ref.path.segments;
-
-        if_chain! {
-            if segments.len() == 1;
-            if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str());
-            if let Some(args) = &segments[0].args;
-            if let ast::GenericArgs::Parenthesized(generic_args) = &**args;
-            if let ast::FnRetTy::Ty(ty) = &generic_args.output;
-            if ty.kind.is_unit();
-            then {
-                lint_unneeded_unit_return(cx, ty, generic_args.span);
-            }
-        }
+            RetReplacement::Block => {
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_RETURN,
+                    ret_span,
+                    "unneeded `return` statement",
+                    "replace `return` with an empty block",
+                    "{}".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            },
+        },
     }
 }
 
-fn attr_is_cfg(attr: &ast::Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
+fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    let mut visitor = BorrowVisitor { cx, borrows: false };
+    walk_expr(&mut visitor, expr);
+    visitor.borrows
 }
 
-// get the def site
-#[must_use]
-fn get_def(span: Span) -> Option<Span> {
-    if span.from_expansion() {
-        Some(span.ctxt().outer_expn_data().def_site)
-    } else {
-        None
-    }
+struct BorrowVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    borrows: bool,
 }
 
-// is this expr a `()` unit?
-fn is_unit_expr(expr: &ast::Expr) -> bool {
-    if let ast::ExprKind::Tup(ref vals) = expr.kind {
-        vals.is_empty()
-    } else {
-        false
+impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
+        if self.borrows {
+            return;
+        }
+
+        if let Some(def_id) = fn_def_id(self.cx, expr) {
+            self.borrows = self
+                .cx
+                .tcx
+                .fn_sig(def_id)
+                .output()
+                .skip_binder()
+                .walk()
+                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
+        }
+
+        walk_expr(self, expr);
     }
-}
 
-fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
-    let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
-        fn_source
-            .rfind("->")
-            .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
-                (
-                    #[allow(clippy::cast_possible_truncation)]
-                    ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
-                    Applicability::MachineApplicable,
-                )
-            })
-    } else {
-        (ty.span, Applicability::MaybeIncorrect)
-    };
-    span_lint_and_sugg(
-        cx,
-        UNUSED_UNIT,
-        ret_span,
-        "unneeded unit return type",
-        "remove the `-> ()`",
-        String::new(),
-        appl,
-    );
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
 }
diff --git a/clippy_lints/src/self_assignment.rs b/clippy_lints/src/self_assignment.rs
new file mode 100644
index 00000000000..e096c9aebc1
--- /dev/null
+++ b/clippy_lints/src/self_assignment.rs
@@ -0,0 +1,51 @@
+use crate::utils::{eq_expr_value, snippet, span_lint};
+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 for explicit self-assignments.
+    ///
+    /// **Why is this bad?** Self-assignments are redundant and unlikely to be
+    /// intentional.
+    ///
+    /// **Known problems:** If expression contains any deref coercions or
+    /// indexing operations they are assumed not to have any side effects.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct Event {
+    ///     id: usize,
+    ///     x: i32,
+    ///     y: i32,
+    /// }
+    ///
+    /// fn copy_position(a: &mut Event, b: &Event) {
+    ///     a.x = b.x;
+    ///     a.y = a.y;
+    /// }
+    /// ```
+    pub SELF_ASSIGNMENT,
+    correctness,
+    "explicit self-assignment"
+}
+
+declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]);
+
+impl<'tcx> LateLintPass<'tcx> for SelfAssignment {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Assign(lhs, rhs, _) = &expr.kind {
+            if eq_expr_value(cx, lhs, rhs) {
+                let lhs = snippet(cx, lhs.span, "<lhs>");
+                let rhs = snippet(cx, rhs.span, "<rhs>");
+                span_lint(
+                    cx,
+                    SELF_ASSIGNMENT,
+                    expr.span,
+                    &format!("self-assignment of `{}` to `{}`", rhs, lhs),
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs
index cd7056620a2..22c49a20451 100644
--- a/clippy_lints/src/stable_sort_primitive.rs
+++ b/clippy_lints/src/stable_sort_primitive.rs
@@ -111,9 +111,9 @@ impl LateLintPass<'_> for StableSortPrimitive {
                 STABLE_SORT_PRIMITIVE,
                 expr.span,
                 format!(
-                    "Use {} instead of {}",
-                    detection.method.unstable_name(),
-                    detection.method.stable_name()
+                    "used {} instead of {}",
+                    detection.method.stable_name(),
+                    detection.method.unstable_name()
                 )
                 .as_str(),
                 "try",
diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs
index 4e335a0222f..3a688a7bbef 100644
--- a/clippy_lints/src/suspicious_trait_impl.rs
+++ b/clippy_lints/src/suspicious_trait_impl.rs
@@ -86,12 +86,20 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
                 cx,
                 expr,
                 binop.node,
-                &["Add", "Sub", "Mul", "Div"],
+                &[
+                    "Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor", "Shl", "Shr",
+                ],
                 &[
                     hir::BinOpKind::Add,
                     hir::BinOpKind::Sub,
                     hir::BinOpKind::Mul,
                     hir::BinOpKind::Div,
+                    hir::BinOpKind::Rem,
+                    hir::BinOpKind::BitAnd,
+                    hir::BinOpKind::BitOr,
+                    hir::BinOpKind::BitXor,
+                    hir::BinOpKind::Shl,
+                    hir::BinOpKind::Shr,
                 ],
             ) {
                 span_lint(
diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs
index 754f87e6b55..cc39f060fc7 100644
--- a/clippy_lints/src/swap.rs
+++ b/clippy_lints/src/swap.rs
@@ -1,7 +1,7 @@
 use crate::utils::sugg::Sugg;
 use crate::utils::{
-    differing_macro_contexts, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty,
-    SpanlessEq,
+    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;
@@ -92,8 +92,8 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
             if rhs2.segments.len() == 1;
 
             if ident.as_str() == rhs2.segments[0].ident.as_str();
-            if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
-            if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
+            if eq_expr_value(cx, tmp_init, lhs1);
+            if eq_expr_value(cx, rhs1, lhs2);
             then {
                 if let ExprKind::Field(ref lhs1, _) = lhs1.kind {
                     if let ExprKind::Field(ref lhs2, _) = lhs2.kind {
@@ -193,7 +193,7 @@ enum Slice<'a> {
 fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> {
     if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
         if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
-            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
+            if eq_expr_value(cx, lhs1, lhs2) {
                 let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
 
                 if matches!(ty.kind, ty::Slice(_))
@@ -221,8 +221,8 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
             if !differing_macro_contexts(first.span, second.span);
             if let ExprKind::Assign(ref lhs0, ref rhs0, _) = first.kind;
             if let ExprKind::Assign(ref lhs1, ref rhs1, _) = second.kind;
-            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
-            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
+            if eq_expr_value(cx, lhs0, rhs1);
+            if eq_expr_value(cx, lhs1, rhs0);
             then {
                 let lhs0 = Sugg::hir_opt(cx, lhs0);
                 let rhs0 = Sugg::hir_opt(cx, rhs0);
diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs
new file mode 100644
index 00000000000..11bdd27d9b1
--- /dev/null
+++ b/clippy_lints/src/to_string_in_display.rs
@@ -0,0 +1,100 @@
+use crate::utils::{match_def_path, match_trait_method, paths, span_lint};
+use if_chain::if_chain;
+use rustc_hir::{Expr, ExprKind, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for uses of `to_string()` in `Display` traits.
+    ///
+    /// **Why is this bad?** Usually `to_string` is implemented indirectly
+    /// via `Display`. Hence using it while implementing `Display` would
+    /// lead to infinite recursion.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::fmt;
+    ///
+    /// struct Structure(i32);
+    /// impl fmt::Display for Structure {
+    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    ///         write!(f, "{}", self.to_string())
+    ///     }
+    /// }
+    ///
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::fmt;
+    ///
+    /// struct Structure(i32);
+    /// impl fmt::Display for Structure {
+    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    ///         write!(f, "{}", self.0)
+    ///     }
+    /// }
+    /// ```
+    pub TO_STRING_IN_DISPLAY,
+    correctness,
+    "to_string method used while implementing Display trait"
+}
+
+#[derive(Default)]
+pub struct ToStringInDisplay {
+    in_display_impl: bool,
+}
+
+impl ToStringInDisplay {
+    pub fn new() -> Self {
+        Self { in_display_impl: false }
+    }
+}
+
+impl_lint_pass!(ToStringInDisplay => [TO_STRING_IN_DISPLAY]);
+
+impl LateLintPass<'_> for ToStringInDisplay {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if is_display_impl(cx, item) {
+            self.in_display_impl = true;
+        }
+    }
+
+    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if is_display_impl(cx, item) {
+            self.in_display_impl = false;
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if_chain! {
+            if let ExprKind::MethodCall(ref path, _, _, _) = expr.kind;
+            if path.ident.name == sym!(to_string);
+            if match_trait_method(cx, expr, &paths::TO_STRING);
+            if self.in_display_impl;
+
+            then {
+                span_lint(
+                    cx,
+                    TO_STRING_IN_DISPLAY,
+                    expr.span,
+                    "Using to_string in fmt::Display implementation might lead to infinite recursion",
+                );
+            }
+        }
+    }
+}
+
+fn is_display_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
+    if_chain! {
+        if let ItemKind::Impl { of_trait: Some(trait_ref), .. } = &item.kind;
+        if let Some(did) = trait_ref.trait_def_id();
+        then {
+            match_def_path(cx, did, &paths::DISPLAY_TRAIT)
+        } else {
+            false
+        }
+    }
+}
diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs
index 28fd55f6ff0..50d9c93f9d4 100644
--- a/clippy_lints/src/transmute.rs
+++ b/clippy_lints/src/transmute.rs
@@ -1,5 +1,5 @@
 use crate::utils::{
-    is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg,
+    in_constant, is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg,
     span_lint_and_then, sugg,
 };
 use if_chain::if_chain;
@@ -331,6 +331,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
             if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::TRANSMUTE);
             then {
+                // Avoid suggesting from/to bits in const contexts.
+                // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
+                let const_context = in_constant(cx, e.hir_id);
+
                 let from_ty = cx.typeck_results().expr_ty(&args[0]);
                 let to_ty = cx.typeck_results().expr_ty(e);
 
@@ -544,7 +548,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                             },
                         )
                     },
-                    (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then(
+                    (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => span_lint_and_then(
                         cx,
                         TRANSMUTE_INT_TO_FLOAT,
                         e.span,
@@ -567,7 +571,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                             );
                         },
                     ),
-                    (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then(
+                    (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => span_lint_and_then(
                         cx,
                         TRANSMUTE_FLOAT_TO_INT,
                         e.span,
diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs
index a74104e9282..a4676e505b6 100644
--- a/clippy_lints/src/try_err.rs
+++ b/clippy_lints/src/try_err.rs
@@ -1,10 +1,10 @@
 use crate::utils::{
-    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
-    snippet_with_macro_callsite, span_lint_and_sugg,
+    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
+    span_lint_and_sugg,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource};
+use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs
index 0fd70550fa0..7e9190bef5e 100644
--- a/clippy_lints/src/types.rs
+++ b/clippy_lints/src/types.rs
@@ -353,14 +353,25 @@ impl Types {
                             );
                             return; // don't recurse into the type
                         }
-                        if let Some(span) = match_type_parameter(cx, qpath, &paths::BOX) {
+                        if match_type_parameter(cx, qpath, &paths::BOX).is_some() {
+                            let box_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(&box_ty).args.unwrap().args[0] {
+                                GenericArg::Type(ty) => ty.span,
+                                _ => return,
+                            };
                             span_lint_and_sugg(
                                 cx,
                                 REDUNDANT_ALLOCATION,
                                 hir_ty.span,
                                 "usage of `Rc<Box<T>>`",
                                 "try",
-                                snippet(cx, span, "..").to_string(),
+                                format!("Rc<{}>", snippet(cx, inner_span, "..")),
                                 Applicability::MachineApplicable,
                             );
                             return; // don't recurse into the type
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 9fe771cef45..0dca6a5da0c 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -2,9 +2,9 @@
 
 use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
 use crate::utils::{over, span_lint_and_then};
-use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs
new file mode 100644
index 00000000000..7548c6afa97
--- /dev/null
+++ b/clippy_lints/src/unused_unit.rs
@@ -0,0 +1,144 @@
+use if_chain::if_chain;
+use rustc_ast::ast;
+use rustc_ast::visit::FnKind;
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
+use rustc_span::BytePos;
+
+use crate::utils::span_lint_and_sugg;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
+    ///
+    /// **Why is this bad?** Such expressions add no value, but can make the code
+    /// less readable. Depending on formatting they can make a `break` or `return`
+    /// statement look like a function call.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn return_unit() -> () {
+    ///     ()
+    /// }
+    /// ```
+    pub UNUSED_UNIT,
+    style,
+    "needless unit expression"
+}
+
+declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
+
+impl EarlyLintPass for UnusedUnit {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
+        if_chain! {
+            if let ast::FnRetTy::Ty(ref ty) = kind.decl().output;
+            if let ast::TyKind::Tup(ref vals) = ty.kind;
+            if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
+            then {
+                lint_unneeded_unit_return(cx, ty, span);
+            }
+        }
+    }
+
+    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
+        if_chain! {
+            if let Some(ref stmt) = block.stmts.last();
+            if let ast::StmtKind::Expr(ref expr) = stmt.kind;
+            if is_unit_expr(expr) && !stmt.span.from_expansion();
+            then {
+                let sp = expr.span;
+                span_lint_and_sugg(
+                    cx,
+                    UNUSED_UNIT,
+                    sp,
+                    "unneeded unit expression",
+                    "remove the final `()`",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
+        match e.kind {
+            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
+                if is_unit_expr(expr) && !expr.span.from_expansion() {
+                    span_lint_and_sugg(
+                        cx,
+                        UNUSED_UNIT,
+                        expr.span,
+                        "unneeded `()`",
+                        "remove the `()`",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            },
+            _ => (),
+        }
+    }
+
+    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
+        let segments = &poly.trait_ref.path.segments;
+
+        if_chain! {
+            if segments.len() == 1;
+            if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str());
+            if let Some(args) = &segments[0].args;
+            if let ast::GenericArgs::Parenthesized(generic_args) = &**args;
+            if let ast::FnRetTy::Ty(ty) = &generic_args.output;
+            if ty.kind.is_unit();
+            then {
+                lint_unneeded_unit_return(cx, ty, generic_args.span);
+            }
+        }
+    }
+}
+
+// get the def site
+#[must_use]
+fn get_def(span: Span) -> Option<Span> {
+    if span.from_expansion() {
+        Some(span.ctxt().outer_expn_data().def_site)
+    } else {
+        None
+    }
+}
+
+// is this expr a `()` unit?
+fn is_unit_expr(expr: &ast::Expr) -> bool {
+    if let ast::ExprKind::Tup(ref vals) = expr.kind {
+        vals.is_empty()
+    } else {
+        false
+    }
+}
+
+fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
+    let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
+        fn_source
+            .rfind("->")
+            .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+                (
+                    #[allow(clippy::cast_possible_truncation)]
+                    ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+                    Applicability::MachineApplicable,
+                )
+            })
+    } else {
+        (ty.span, Applicability::MaybeIncorrect)
+    };
+    span_lint_and_sugg(
+        cx,
+        UNUSED_UNIT,
+        ret_span,
+        "unneeded unit return type",
+        "remove the `-> ()`",
+        String::new(),
+        appl,
+    );
+}
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index 776c6bc57ca..427a1b65773 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -50,7 +50,7 @@ declare_clippy_lint! {
     /// ```
     pub USE_SELF,
     nursery,
-    "Unnecessary structure name repetition whereas `Self` is applicable"
+    "unnecessary structure name repetition whereas `Self` is applicable"
 }
 
 declare_lint_pass!(UseSelf => [USE_SELF]);
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 1bf37632e32..4ab2b5e796d 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -1,3 +1,4 @@
+use crate::utils::sugg::Sugg;
 use crate::utils::{
     get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet,
     snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg,
@@ -158,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             if TyS::same_type(a, b);
 
                             then {
-                                let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
+                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
                                 let sugg_msg =
                                     format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                 span_lint_and_sugg(
@@ -167,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                                     e.span,
                                     "useless conversion to the same type",
                                     &sugg_msg,
-                                    sugg,
+                                    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 c32c80dcd3c..7b419431c0f 100644
--- a/clippy_lints/src/utils/ast_utils.rs
+++ b/clippy_lints/src/utils/ast_utils.rs
@@ -5,8 +5,8 @@
 #![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
 
 use crate::utils::{both, over};
-use rustc_ast::{self as ast, *};
 use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, *};
 use rustc_span::symbol::Ident;
 use std::mem;
 
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 9b7a268c628..6eda6d1fa83 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -175,18 +175,15 @@ impl PrintVisitor {
     }
 
     fn print_qpath(&mut self, path: &QPath<'_>) {
-        match  *path {
-            QPath::LangItem(lang_item, _) => {
-                println!(
-                    "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
-                   self.current, lang_item,
-                );
-            },
-            _ => {
-                print!("    if match_qpath({}, &[", self.current);
-                print_path(path, &mut true);
-                println!("]);");
-            },
+        if let QPath::LangItem(lang_item, _) = *path {
+            println!(
+                "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
+                self.current, lang_item,
+            );
+        } else {
+            print!("    if match_qpath({}, &[", self.current);
+            print_path(path, &mut true);
+            println!("]);");
         }
     }
 }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index ba3492a6fff..292dbd7ad6b 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -138,7 +138,7 @@ define_Conf! {
     (type_complexity_threshold, "type_complexity_threshold": u64, 250),
     /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
     (single_char_binding_names_threshold, "single_char_binding_names_threshold": u64, 4),
-    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
+    /// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
     (too_large_for_stack, "too_large_for_stack": u64, 200),
     /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
     (enum_variant_name_threshold, "enum_variant_name_threshold": u64, 3),
diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs
index ba15456014d..8563b469a30 100644
--- a/clippy_lints/src/utils/higher.rs
+++ b/clippy_lints/src/utils/higher.rs
@@ -56,43 +56,45 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
     }
 
     match expr.kind {
-        hir::ExprKind::Call(ref path, ref args) if matches!(
-            path.kind,
-            hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
-        ) => Some(Range {
-            start: Some(&args[0]),
-            end: Some(&args[1]),
-            limits: ast::RangeLimits::Closed,
-        }),
-        hir::ExprKind::Struct(ref path, ref fields, None) => {
-            match path {
-                hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
-                    start: None,
-                    end: None,
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
-                    start: Some(get_field("start", fields)?),
-                    end: None,
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
-                    start: Some(get_field("start", fields)?),
-                    end: Some(get_field("end", fields)?),
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
-                    start: None,
-                    end: Some(get_field("end", fields)?),
-                    limits: ast::RangeLimits::Closed,
-                }),
-                hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
-                    start: None,
-                    end: Some(get_field("end", fields)?),
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                _ => None,
-            }
+        hir::ExprKind::Call(ref path, ref args)
+            if matches!(
+                path.kind,
+                hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
+            ) =>
+        {
+            Some(Range {
+                start: Some(&args[0]),
+                end: Some(&args[1]),
+                limits: ast::RangeLimits::Closed,
+            })
+        },
+        hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+            hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
+                start: None,
+                end: None,
+                limits: ast::RangeLimits::HalfOpen,
+            }),
+            hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
+                start: Some(get_field("start", fields)?),
+                end: None,
+                limits: ast::RangeLimits::HalfOpen,
+            }),
+            hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
+                start: Some(get_field("start", fields)?),
+                end: Some(get_field("end", fields)?),
+                limits: ast::RangeLimits::HalfOpen,
+            }),
+            hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
+                start: None,
+                end: Some(get_field("end", fields)?),
+                limits: ast::RangeLimits::Closed,
+            }),
+            hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
+                start: None,
+                end: Some(get_field("end", fields)?),
+                limits: ast::RangeLimits::HalfOpen,
+            }),
+            _ => None,
         },
         _ => None,
     }
diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs
index 2eefd4a38a6..c7263f48965 100644
--- a/clippy_lints/src/utils/hir_utils.rs
+++ b/clippy_lints/src/utils/hir_utils.rs
@@ -3,9 +3,9 @@ use crate::utils::differing_macro_contexts;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat,
-    FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName,
-    Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, FnRetTy,
+    GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path,
+    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ich::StableHashingContextProvider;
@@ -23,9 +23,7 @@ pub struct SpanlessEq<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    /// If is true, never consider as equal expressions containing function
-    /// calls.
-    ignore_fn: bool,
+    allow_side_effects: bool,
 }
 
 impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
@@ -33,13 +31,14 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            ignore_fn: false,
+            allow_side_effects: true,
         }
     }
 
-    pub fn ignore_fn(self) -> Self {
+    /// Consider expressions containing potential side effects as not equal.
+    pub fn deny_side_effects(self) -> Self {
         Self {
-            ignore_fn: true,
+            allow_side_effects: false,
             ..self
         }
     }
@@ -67,7 +66,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
 
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-        if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
+        if !self.allow_side_effects && differing_macro_contexts(left.span, right.span) {
             return false;
         }
 
@@ -90,10 +89,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
                 both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
             },
             (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
-                self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
+                self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
             (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
-                lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
+                self.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
             (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
             (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
@@ -108,7 +107,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             },
             (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
-                !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
+                self.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
             | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
@@ -134,7 +133,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
                     })
             },
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
-                !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
+                self.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
                 let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
@@ -186,10 +185,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     }
 
     pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
-        match (&left, &right) {
-            (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) =>
-                li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp),
-        }
+        let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right);
+        li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp)
     }
 
     /// Checks whether two patterns are the same.
@@ -233,8 +230,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
-            (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) =>
-                llang_item == rlang_item,
+            (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
             _ => false,
         }
     }
@@ -352,6 +348,11 @@ pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 }
 
+/// Checks if two expressions evaluate to the same value, and don't contain any side effects.
+pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool {
+    SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right)
+}
+
 /// Type used to hash an ast element. This is different from the `Hash` trait
 /// on ast types as this
 /// trait would consider IDs and spans.
@@ -615,7 +616,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             },
             QPath::LangItem(lang_item, ..) => {
                 lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
-            }
+            },
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
@@ -727,7 +728,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 },
                 QPath::LangItem(lang_item, ..) => {
                     lang_item.hash(&mut self.s);
-                }
+                },
             },
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 6c235679914..8fa5d22210a 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -1,7 +1,6 @@
-use crate::utils::SpanlessEq;
 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,
+    span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
@@ -493,7 +492,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
             if let StmtKind::Semi(only_expr) = &stmts[0].kind;
             if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind;
             let and_then_snippets = get_and_then_snippets(cx, and_then_args);
-            let mut sle = SpanlessEq::new(cx).ignore_fn();
+            let mut sle = SpanlessEq::new(cx).deny_side_effects();
             then {
                 match &*ps.ident.as_str() {
                     "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index a56b8203513..2aef995cec4 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -21,7 +21,7 @@ pub mod sugg;
 pub mod usage;
 pub use self::attrs::*;
 pub use self::diagnostics::*;
-pub use self::hir_utils::{both, over, SpanlessEq, SpanlessHash};
+pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
 
 use std::borrow::Cow;
 use std::mem;
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 9c28d63d414..b6a1e0a6aa9 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -84,6 +84,7 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
+pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index f2e76442a19..84e907d7125 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -1,13 +1,20 @@
-use crate::consts::constant;
+use crate::consts::{constant, Constant};
+use crate::rustc_target::abi::LayoutOf;
 use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
+#[allow(clippy::module_name_repetitions)]
+#[derive(Copy, Clone)]
+pub struct UselessVec {
+    pub too_large_for_stack: u64,
+}
+
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
     /// be possible.
@@ -31,7 +38,7 @@ declare_clippy_lint! {
     "useless `vec!`"
 }
 
-declare_lint_pass!(UselessVec => [USELESS_VEC]);
+impl_lint_pass!(UselessVec => [USELESS_VEC]);
 
 impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -42,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
             if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
             then {
-                check_vec_macro(cx, &vec_args, expr.span);
+                self.check_vec_macro(cx, &vec_args, expr.span);
             }
         }
 
@@ -60,46 +67,62 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                     .ctxt()
                     .outer_expn_data()
                     .call_site;
-                check_vec_macro(cx, &vec_args, span);
+                self.check_vec_macro(cx, &vec_args, span);
             }
         }
     }
 }
 
-fn check_vec_macro<'tcx>(cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
-    let mut applicability = Applicability::MachineApplicable;
-    let snippet = match *vec_args {
-        higher::VecArgs::Repeat(elem, len) => {
-            if constant(cx, cx.typeck_results(), len).is_some() {
-                format!(
-                    "&[{}; {}]",
-                    snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
-                    snippet_with_applicability(cx, len.span, "len", &mut applicability)
-                )
-            } else {
-                return;
-            }
-        },
-        higher::VecArgs::Vec(args) => {
-            if let Some(last) = args.iter().last() {
-                let span = args[0].span.to(last.span);
+impl UselessVec {
+    fn check_vec_macro<'tcx>(self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = match *vec_args {
+            higher::VecArgs::Repeat(elem, len) => {
+                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
+                    #[allow(clippy::cast_possible_truncation)]
+                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
+                        return;
+                    }
 
-                format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
-            } else {
-                "&[]".into()
-            }
-        },
-    };
+                    format!(
+                        "&[{}; {}]",
+                        snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
+                        snippet_with_applicability(cx, len.span, "len", &mut applicability)
+                    )
+                } else {
+                    return;
+                }
+            },
+            higher::VecArgs::Vec(args) => {
+                if let Some(last) = args.iter().last() {
+                    #[allow(clippy::cast_possible_truncation)]
+                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
+                        return;
+                    }
+                    let span = args[0].span.to(last.span);
+
+                    format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
+                } else {
+                    "&[]".into()
+                }
+            },
+        };
+
+        span_lint_and_sugg(
+            cx,
+            USELESS_VEC,
+            span,
+            "useless use of `vec!`",
+            "you can use a slice directly",
+            snippet,
+            applicability,
+        );
+    }
+}
 
-    span_lint_and_sugg(
-        cx,
-        USELESS_VEC,
-        span,
-        "useless use of `vec!`",
-        "you can use a slice directly",
-        snippet,
-        applicability,
-    );
+fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
+    let ty = cx.typeck_results().expr_ty_adjusted(expr);
+    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
 }
 
 /// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 063f94582b9..5f88dcb188a 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -237,7 +237,7 @@ impl EarlyLintPass for Write {
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
         if mac.path == sym!(println) {
             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 let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if fmt_str.symbol == Symbol::intern("") {
                     span_lint_and_sugg(
                         cx,
@@ -252,7 +252,7 @@ impl EarlyLintPass for Write {
             }
         } else if mac.path == sym!(print) {
             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 let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if check_newlines(&fmt_str) {
                     span_lint_and_then(
                         cx,
@@ -273,7 +273,7 @@ impl EarlyLintPass for Write {
                 }
             }
         } else if mac.path == sym!(write) {
-            if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
+            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
                 if check_newlines(&fmt_str) {
                     span_lint_and_then(
                         cx,
@@ -294,7 +294,7 @@ impl EarlyLintPass for Write {
                 }
             }
         } else if mac.path == sym!(writeln) {
-            if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
+            if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
                 if fmt_str.symbol == Symbol::intern("") {
                     let mut applicability = Applicability::MachineApplicable;
                     let suggestion = expr.map_or_else(
@@ -364,17 +364,11 @@ impl Write {
     /// (Some("string to write: {}"), Some(buf))
     /// ```
     #[allow(clippy::too_many_lines)]
-    fn check_tts<'a>(
-        &self,
-        cx: &EarlyContext<'a>,
-        tts: &TokenStream,
-        is_write: bool,
-    ) -> (Option<StrLit>, Option<Expr>) {
+    fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
         use rustc_parse_format::{
             AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser,
             Piece,
         };
-        let tts = tts.clone();
 
         let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
         let mut expr: Option<Expr> = None;
diff --git a/doc/adding_lints.md b/doc/adding_lints.md
index 168092f7329..3c782e9b17f 100644
--- a/doc/adding_lints.md
+++ b/doc/adding_lints.md
@@ -295,8 +295,14 @@ impl EarlyLintPass for FooFunctions {
 
 Running our UI test should now produce output that contains the lint message.
 
+According to [the rustc-dev-guide], the text should be matter of fact and avoid
+capitalization and periods, unless multiple sentences are needed.
+When code or an identifier must appear in a message or label, it should be
+surrounded with single acute accents \`.
+
 [check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
 [diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
+[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html
 
 ## Adding the lint logic
 
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index bbb300296be..bf58c117aaa 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -1037,7 +1037,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         group: "style",
         desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block",
         deprecation: None,
-        module: "let_and_return",
+        module: "returns",
     },
     Lint {
         name: "let_underscore_lock",
@@ -1957,6 +1957,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "methods",
     },
     Lint {
+        name: "self_assignment",
+        group: "correctness",
+        desc: "explicit self-assignment",
+        deprecation: None,
+        module: "self_assignment",
+    },
+    Lint {
         name: "serde_api_misuse",
         group: "correctness",
         desc: "various things that will negatively affect your serde experience",
@@ -2013,6 +2020,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "methods",
     },
     Lint {
+        name: "single_char_push_str",
+        group: "style",
+        desc: "`push_str()` used with a single-character string literal as parameter",
+        deprecation: None,
+        module: "methods",
+    },
+    Lint {
         name: "single_component_path_imports",
         group: "style",
         desc: "imports with single component path are redundant",
@@ -2167,6 +2181,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "to_digit_is_some",
     },
     Lint {
+        name: "to_string_in_display",
+        group: "correctness",
+        desc: "to_string method used while implementing Display trait",
+        deprecation: None,
+        module: "to_string_in_display",
+    },
+    Lint {
         name: "todo",
         group: "restriction",
         desc: "`todo!` should not be present in production code",
@@ -2370,6 +2391,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "methods",
     },
     Lint {
+        name: "unnecessary_lazy_evaluations",
+        group: "style",
+        desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation",
+        deprecation: None,
+        module: "methods",
+    },
+    Lint {
         name: "unnecessary_mut_passed",
         group: "style",
         desc: "an argument passed as a mutable reference although the callee only demands an immutable reference",
@@ -2479,7 +2507,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         group: "style",
         desc: "needless unit expression",
         deprecation: None,
-        module: "returns",
+        module: "unused_unit",
     },
     Lint {
         name: "unwrap_used",
@@ -2498,7 +2526,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     Lint {
         name: "use_self",
         group: "nursery",
-        desc: "Unnecessary structure name repetition whereas `Self` is applicable",
+        desc: "unnecessary structure name repetition whereas `Self` is applicable",
         deprecation: None,
         module: "use_self",
     },
diff --git a/tests/ui/duration_subsec.stderr b/tests/ui/duration_subsec.stderr
index bd8adc2c570..cdbeff6a037 100644
--- a/tests/ui/duration_subsec.stderr
+++ b/tests/ui/duration_subsec.stderr
@@ -1,4 +1,4 @@
-error: Calling `subsec_millis()` is more concise than this calculation
+error: calling `subsec_millis()` is more concise than this calculation
   --> $DIR/duration_subsec.rs:10:24
    |
 LL |     let bad_millis_1 = dur.subsec_micros() / 1_000;
@@ -6,25 +6,25 @@ LL |     let bad_millis_1 = dur.subsec_micros() / 1_000;
    |
    = note: `-D clippy::duration-subsec` implied by `-D warnings`
 
-error: Calling `subsec_millis()` is more concise than this calculation
+error: calling `subsec_millis()` is more concise than this calculation
   --> $DIR/duration_subsec.rs:11:24
    |
 LL |     let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
 
-error: Calling `subsec_micros()` is more concise than this calculation
+error: calling `subsec_micros()` is more concise than this calculation
   --> $DIR/duration_subsec.rs:16:22
    |
 LL |     let bad_micros = dur.subsec_nanos() / 1_000;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
 
-error: Calling `subsec_micros()` is more concise than this calculation
+error: calling `subsec_micros()` is more concise than this calculation
   --> $DIR/duration_subsec.rs:21:13
    |
 LL |     let _ = (&dur).subsec_nanos() / 1_000;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()`
 
-error: Calling `subsec_micros()` is more concise than this calculation
+error: calling `subsec_micros()` is more concise than this calculation
   --> $DIR/duration_subsec.rs:25:13
    |
 LL |     let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
diff --git a/tests/ui/enum_clike_unportable_variant.stderr b/tests/ui/enum_clike_unportable_variant.stderr
index 71f3f5e083e..5935eea5e03 100644
--- a/tests/ui/enum_clike_unportable_variant.stderr
+++ b/tests/ui/enum_clike_unportable_variant.stderr
@@ -1,4 +1,4 @@
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:8:5
    |
 LL |     X = 0x1_0000_0000,
@@ -6,49 +6,49 @@ LL |     X = 0x1_0000_0000,
    |
    = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings`
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:15:5
    |
 LL |     X = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:18:5
    |
 LL |     A = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:25:5
    |
 LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:26:5
    |
 LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:28:5
    |
 LL |     C = (i32::MIN as isize) - 1,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:34:5
    |
 LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:35:5
    |
 LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
-error: Clike enum variant discriminant is not portable to 32-bit targets
+error: C-like enum variant discriminant is not portable to 32-bit targets
   --> $DIR/enum_clike_unportable_variant.rs:40:5
    |
 LL |     X = <usize as Trait>::Number,
diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr
index 2835391de7f..b1d481190ff 100644
--- a/tests/ui/enum_variants.stderr
+++ b/tests/ui/enum_variants.stderr
@@ -1,4 +1,4 @@
-error: Variant name ends with the enum's name
+error: variant name ends with the enum's name
   --> $DIR/enum_variants.rs:16:5
    |
 LL |     cFoo,
@@ -6,25 +6,25 @@ LL |     cFoo,
    |
    = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 
-error: Variant name starts with the enum's name
+error: variant name starts with the enum's name
   --> $DIR/enum_variants.rs:27:5
    |
 LL |     FoodGood,
    |     ^^^^^^^^
 
-error: Variant name starts with the enum's name
+error: variant name starts with the enum's name
   --> $DIR/enum_variants.rs:28:5
    |
 LL |     FoodMiddle,
    |     ^^^^^^^^^^
 
-error: Variant name starts with the enum's name
+error: variant name starts with the enum's name
   --> $DIR/enum_variants.rs:29:5
    |
 LL |     FoodBad,
    |     ^^^^^^^
 
-error: All variants have the same prefix: `Food`
+error: all variants have the same prefix: `Food`
   --> $DIR/enum_variants.rs:26:1
    |
 LL | / enum Food {
@@ -36,7 +36,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: All variants have the same prefix: `CallType`
+error: all variants have the same prefix: `CallType`
   --> $DIR/enum_variants.rs:36:1
    |
 LL | / enum BadCallType {
@@ -48,7 +48,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: All variants have the same prefix: `Constant`
+error: all variants have the same prefix: `Constant`
   --> $DIR/enum_variants.rs:48:1
    |
 LL | / enum Consts {
@@ -60,7 +60,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: All variants have the same prefix: `With`
+error: all variants have the same prefix: `With`
   --> $DIR/enum_variants.rs:82:1
    |
 LL | / enum Seallll {
@@ -72,7 +72,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: All variants have the same prefix: `Prefix`
+error: all variants have the same prefix: `Prefix`
   --> $DIR/enum_variants.rs:88:1
    |
 LL | / enum NonCaps {
@@ -84,7 +84,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: All variants have the same prefix: `With`
+error: all variants have the same prefix: `With`
   --> $DIR/enum_variants.rs:94:1
    |
 LL | / pub enum PubSeall {
diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr
index 334ccb01016..6afee0f36b9 100644
--- a/tests/ui/if_let_some_result.stderr
+++ b/tests/ui/if_let_some_result.stderr
@@ -1,22 +1,22 @@
-error: Matching on `Some` with `ok()` is redundant
+error: matching on `Some` with `ok()` is redundant
   --> $DIR/if_let_some_result.rs:6:5
    |
 LL |     if let Some(y) = x.parse().ok() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::if-let-some-result` implied by `-D warnings`
-help: Consider matching on `Ok(y)` and removing the call to `ok` instead
+help: consider matching on `Ok(y)` and removing the call to `ok` instead
    |
 LL |     if let Ok(y) = x.parse() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Matching on `Some` with `ok()` is redundant
+error: matching on `Some` with `ok()` is redundant
   --> $DIR/if_let_some_result.rs:24:9
    |
 LL |         if let Some(y) = x   .   parse()   .   ok   ()    {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: Consider matching on `Ok(y)` and removing the call to `ok` instead
+help: consider matching on `Ok(y)` and removing the call to `ok` instead
    |
 LL |         if let Ok(y) = x   .   parse()       {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr
index 78bc4d4bd20..53d1b86d02a 100644
--- a/tests/ui/if_not_else.stderr
+++ b/tests/ui/if_not_else.stderr
@@ -1,4 +1,4 @@
-error: Unnecessary boolean `not` operation
+error: unnecessary boolean `not` operation
   --> $DIR/if_not_else.rs:9:5
    |
 LL | /     if !bla() {
@@ -11,7 +11,7 @@ LL | |     }
    = note: `-D clippy::if-not-else` implied by `-D warnings`
    = help: remove the `!` and swap the blocks of the `if`/`else`
 
-error: Unnecessary `!=` operation
+error: unnecessary `!=` operation
   --> $DIR/if_not_else.rs:14:5
    |
 LL | /     if 4 != 5 {
diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr
index 585d32845d2..aab688cc2d8 100644
--- a/tests/ui/impl.stderr
+++ b/tests/ui/impl.stderr
@@ -1,4 +1,4 @@
-error: Multiple implementations of this structure
+error: multiple implementations of this structure
   --> $DIR/impl.rs:10:1
    |
 LL | / impl MyStruct {
@@ -7,7 +7,7 @@ LL | | }
    | |_^
    |
    = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
-note: First implementation here
+note: first implementation here
   --> $DIR/impl.rs:6:1
    |
 LL | / impl MyStruct {
@@ -15,7 +15,7 @@ LL | |     fn first() {}
 LL | | }
    | |_^
 
-error: Multiple implementations of this structure
+error: multiple implementations of this structure
   --> $DIR/impl.rs:24:5
    |
 LL | /     impl super::MyStruct {
@@ -23,7 +23,7 @@ LL | |         fn third() {}
 LL | |     }
    | |_____^
    |
-note: First implementation here
+note: first implementation here
   --> $DIR/impl.rs:6:1
    |
 LL | / impl MyStruct {
diff --git a/tests/ui/implicit_saturating_sub.stderr b/tests/ui/implicit_saturating_sub.stderr
index 2eb2023b3b9..5bb9a606422 100644
--- a/tests/ui/implicit_saturating_sub.stderr
+++ b/tests/ui/implicit_saturating_sub.stderr
@@ -1,4 +1,4 @@
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:13:5
    |
 LL | /     if u_8 > 0 {
@@ -8,7 +8,7 @@ LL | |     }
    |
    = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:20:13
    |
 LL | /             if u_8 > 0 {
@@ -16,7 +16,7 @@ LL | |                 u_8 -= 1;
 LL | |             }
    | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:34:5
    |
 LL | /     if u_16 > 0 {
@@ -24,7 +24,7 @@ LL | |         u_16 -= 1;
 LL | |     }
    | |_____^ help: try: `u_16 = u_16.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:44:5
    |
 LL | /     if u_32 != 0 {
@@ -32,7 +32,7 @@ LL | |         u_32 -= 1;
 LL | |     }
    | |_____^ help: try: `u_32 = u_32.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:65:5
    |
 LL | /     if u_64 > 0 {
@@ -40,7 +40,7 @@ LL | |         u_64 -= 1;
 LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:70:5
    |
 LL | /     if 0 < u_64 {
@@ -48,7 +48,7 @@ LL | |         u_64 -= 1;
 LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:75:5
    |
 LL | /     if 0 != u_64 {
@@ -56,7 +56,7 @@ LL | |         u_64 -= 1;
 LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:96:5
    |
 LL | /     if u_usize > 0 {
@@ -64,7 +64,7 @@ LL | |         u_usize -= 1;
 LL | |     }
    | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:108:5
    |
 LL | /     if i_8 > i8::MIN {
@@ -72,7 +72,7 @@ LL | |         i_8 -= 1;
 LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:113:5
    |
 LL | /     if i_8 > i8::MIN {
@@ -80,7 +80,7 @@ LL | |         i_8 -= 1;
 LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:118:5
    |
 LL | /     if i_8 != i8::MIN {
@@ -88,7 +88,7 @@ LL | |         i_8 -= 1;
 LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:123:5
    |
 LL | /     if i_8 != i8::MIN {
@@ -96,7 +96,7 @@ LL | |         i_8 -= 1;
 LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:133:5
    |
 LL | /     if i_16 > i16::MIN {
@@ -104,7 +104,7 @@ LL | |         i_16 -= 1;
 LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:138:5
    |
 LL | /     if i_16 > i16::MIN {
@@ -112,7 +112,7 @@ LL | |         i_16 -= 1;
 LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:143:5
    |
 LL | /     if i_16 != i16::MIN {
@@ -120,7 +120,7 @@ LL | |         i_16 -= 1;
 LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:148:5
    |
 LL | /     if i_16 != i16::MIN {
@@ -128,7 +128,7 @@ LL | |         i_16 -= 1;
 LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:158:5
    |
 LL | /     if i_32 > i32::MIN {
@@ -136,7 +136,7 @@ LL | |         i_32 -= 1;
 LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:163:5
    |
 LL | /     if i_32 > i32::MIN {
@@ -144,7 +144,7 @@ LL | |         i_32 -= 1;
 LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:168:5
    |
 LL | /     if i_32 != i32::MIN {
@@ -152,7 +152,7 @@ LL | |         i_32 -= 1;
 LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:173:5
    |
 LL | /     if i_32 != i32::MIN {
@@ -160,7 +160,7 @@ LL | |         i_32 -= 1;
 LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:183:5
    |
 LL | /     if i64::MIN < i_64 {
@@ -168,7 +168,7 @@ LL | |         i_64 -= 1;
 LL | |     }
    | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:188:5
    |
 LL | /     if i64::MIN != i_64 {
@@ -176,7 +176,7 @@ LL | |         i_64 -= 1;
 LL | |     }
    | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 
-error: Implicitly performing saturating subtraction
+error: implicitly performing saturating subtraction
   --> $DIR/implicit_saturating_sub.rs:193:5
    |
 LL | /     if i64::MIN < i_64 {
diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr
index 29a6914761c..c5b020ba8ce 100644
--- a/tests/ui/int_plus_one.stderr
+++ b/tests/ui/int_plus_one.stderr
@@ -1,4 +1,4 @@
-error: Unnecessary `>= y + 1` or `x - 1 >=`
+error: unnecessary `>= y + 1` or `x - 1 >=`
   --> $DIR/int_plus_one.rs:9:13
    |
 LL |     let _ = x >= y + 1;
@@ -6,19 +6,19 @@ LL |     let _ = x >= y + 1;
    |
    = note: `-D clippy::int-plus-one` implied by `-D warnings`
 
-error: Unnecessary `>= y + 1` or `x - 1 >=`
+error: unnecessary `>= y + 1` or `x - 1 >=`
   --> $DIR/int_plus_one.rs:10:13
    |
 LL |     let _ = y + 1 <= x;
    |             ^^^^^^^^^^ help: change it to: `y < x`
 
-error: Unnecessary `>= y + 1` or `x - 1 >=`
+error: unnecessary `>= y + 1` or `x - 1 >=`
   --> $DIR/int_plus_one.rs:12:13
    |
 LL |     let _ = x - 1 >= y;
    |             ^^^^^^^^^^ help: change it to: `x > y`
 
-error: Unnecessary `>= y + 1` or `x - 1 >=`
+error: unnecessary `>= y + 1` or `x - 1 >=`
   --> $DIR/int_plus_one.rs:13:13
    |
 LL |     let _ = y <= x - 1;
diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr
index bbf61df0cda..8c10a252ee0 100644
--- a/tests/ui/iter_next_slice.stderr
+++ b/tests/ui/iter_next_slice.stderr
@@ -1,4 +1,4 @@
-error: Using `.iter().next()` on an array
+error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:9:5
    |
 LL |     s.iter().next();
@@ -6,19 +6,19 @@ LL |     s.iter().next();
    |
    = note: `-D clippy::iter-next-slice` implied by `-D warnings`
 
-error: Using `.iter().next()` on a Slice without end index.
+error: using `.iter().next()` on a Slice without end index
   --> $DIR/iter_next_slice.rs:12:5
    |
 LL |     s[2..].iter().next();
    |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)`
 
-error: Using `.iter().next()` on a Slice without end index.
+error: using `.iter().next()` on a Slice without end index
   --> $DIR/iter_next_slice.rs:15:5
    |
 LL |     v[5..].iter().next();
    |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)`
 
-error: Using `.iter().next()` on an array
+error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:18:5
    |
 LL |     v.iter().next();
diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr
index 9eec6928e8c..4f43cff5024 100644
--- a/tests/ui/map_clone.stderr
+++ b/tests/ui/map_clone.stderr
@@ -1,40 +1,40 @@
-error: You are using an explicit closure for copying elements
+error: you are using an explicit closure for copying elements
   --> $DIR/map_clone.rs:10:22
    |
 LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
    |
    = note: `-D clippy::map-clone` implied by `-D warnings`
 
-error: You are using an explicit closure for cloning elements
+error: you are using an explicit closure for cloning elements
   --> $DIR/map_clone.rs:11:26
    |
 LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
 
-error: You are using an explicit closure for copying elements
+error: you are using an explicit closure for copying elements
   --> $DIR/map_clone.rs:12:23
    |
 LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
 
-error: You are using an explicit closure for copying elements
+error: you are using an explicit closure for copying elements
   --> $DIR/map_clone.rs:14:26
    |
 LL |     let _: Option<u64> = Some(&16).map(|b| *b);
-   |                          ^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&16).copied()`
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
 
-error: You are using an explicit closure for copying elements
+error: you are using an explicit closure for copying elements
   --> $DIR/map_clone.rs:15:25
    |
 LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&1).copied()`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
 
-error: You are needlessly cloning iterator elements
+error: you are needlessly cloning iterator elements
   --> $DIR/map_clone.rs:26:29
    |
 LL |     let _ = std::env::args().map(|v| v.clone());
-   |                             ^^^^^^^^^^^^^^^^^^^ help: Remove the `map` call
+   |                             ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs
index 7880cf36415..80dd2f744b3 100644
--- a/tests/ui/methods.rs
+++ b/tests/ui/methods.rs
@@ -10,6 +10,7 @@
     clippy::non_ascii_literal,
     clippy::new_without_default,
     clippy::needless_pass_by_value,
+    clippy::needless_lifetimes,
     clippy::print_stdout,
     clippy::must_use_candidate,
     clippy::use_self,
@@ -33,71 +34,6 @@ use std::sync::{self, Arc};
 
 use option_helpers::IteratorFalsePositives;
 
-pub struct T;
-
-impl T {
-    pub fn add(self, other: T) -> T {
-        self
-    }
-
-    // no error, not public interface
-    pub(crate) fn drop(&mut self) {}
-
-    // no error, private function
-    fn neg(self) -> Self {
-        self
-    }
-
-    // no error, private function
-    fn eq(&self, other: T) -> bool {
-        true
-    }
-
-    // No error; self is a ref.
-    fn sub(&self, other: T) -> &T {
-        self
-    }
-
-    // No error; different number of arguments.
-    fn div(self) -> T {
-        self
-    }
-
-    // No error; wrong return type.
-    fn rem(self, other: T) {}
-
-    // Fine
-    fn into_u32(self) -> u32 {
-        0
-    }
-
-    fn into_u16(&self) -> u16 {
-        0
-    }
-
-    fn to_something(self) -> u32 {
-        0
-    }
-
-    fn new(self) -> Self {
-        unimplemented!();
-    }
-}
-
-pub struct T1;
-
-impl T1 {
-    // Shouldn't trigger lint as it is unsafe.
-    pub unsafe fn add(self, rhs: T1) -> T1 {
-        self
-    }
-
-    // Should not trigger lint since this is an async function.
-    pub async fn next(&mut self) -> Option<T1> {
-        None
-    }
-}
-
 struct Lt<'a> {
     foo: &'a u32,
 }
@@ -171,6 +107,8 @@ impl BadNew {
     }
 }
 
+struct T;
+
 impl Mul<T> for T {
     type Output = T;
     // No error, obviously.
diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr
index 01cf487ac14..2a0a43e83a6 100644
--- a/tests/ui/methods.stderr
+++ b/tests/ui/methods.stderr
@@ -1,15 +1,5 @@
-error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
-  --> $DIR/methods.rs:39:5
-   |
-LL | /     pub fn add(self, other: T) -> T {
-LL | |         self
-LL | |     }
-   | |_____^
-   |
-   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
-
 error: methods called `new` usually return `Self`
-  --> $DIR/methods.rs:169:5
+  --> $DIR/methods.rs:105:5
    |
 LL | /     fn new() -> i32 {
 LL | |         0
@@ -19,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-  --> $DIR/methods.rs:188:13
+  --> $DIR/methods.rs:126:13
    |
 LL |     let _ = v.iter().filter(|&x| *x < 0).next();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +18,7 @@ LL |     let _ = v.iter().filter(|&x| *x < 0).next();
    = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
 
 error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-  --> $DIR/methods.rs:191:13
+  --> $DIR/methods.rs:129:13
    |
 LL |       let _ = v.iter().filter(|&x| {
    |  _____________^
@@ -38,7 +28,7 @@ LL | |                    ).next();
    | |___________________________^
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:208:22
+  --> $DIR/methods.rs:146:22
    |
 LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
@@ -46,25 +36,25 @@ LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    = note: `-D clippy::search-is-some` implied by `-D warnings`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:209:20
+  --> $DIR/methods.rs:147:20
    |
 LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:210:20
+  --> $DIR/methods.rs:148:20
    |
 LL |     let _ = (0..1).find(|x| *x == 0).is_some();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:211:22
+  --> $DIR/methods.rs:149:22
    |
 LL |     let _ = v.iter().find(|x| **x == 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:214:13
+  --> $DIR/methods.rs:152:13
    |
 LL |       let _ = v.iter().find(|&x| {
    |  _____________^
@@ -74,13 +64,13 @@ LL | |                    ).is_some();
    | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:220:22
+  --> $DIR/methods.rs:158:22
    |
 LL |     let _ = v.iter().position(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:223:13
+  --> $DIR/methods.rs:161:13
    |
 LL |       let _ = v.iter().position(|&x| {
    |  _____________^
@@ -90,13 +80,13 @@ LL | |                    ).is_some();
    | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:229:22
+  --> $DIR/methods.rs:167:22
    |
 LL |     let _ = v.iter().rposition(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:232:13
+  --> $DIR/methods.rs:170:13
    |
 LL |       let _ = v.iter().rposition(|&x| {
    |  _____________^
@@ -105,5 +95,5 @@ LL | |                                }
 LL | |                    ).is_some();
    | |______________________________^
 
-error: aborting due to 13 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr
index fa8c82ae0f3..062d30b262c 100644
--- a/tests/ui/mut_reference.stderr
+++ b/tests/ui/mut_reference.stderr
@@ -1,4 +1,4 @@
-error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
+error: the function `takes_an_immutable_reference` doesn't need a mutable reference
   --> $DIR/mut_reference.rs:17:34
    |
 LL |     takes_an_immutable_reference(&mut 42);
@@ -6,13 +6,13 @@ LL |     takes_an_immutable_reference(&mut 42);
    |
    = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
 
-error: The function/method `as_ptr` doesn't need a mutable reference
+error: the function `as_ptr` doesn't need a mutable reference
   --> $DIR/mut_reference.rs:19:12
    |
 LL |     as_ptr(&mut 42);
    |            ^^^^^^^
 
-error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
+error: the method `takes_an_immutable_reference` doesn't need a mutable reference
   --> $DIR/mut_reference.rs:23:44
    |
 LL |     my_struct.takes_an_immutable_reference(&mut 42);
diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr
index 7dac0865855..a3511ba708a 100644
--- a/tests/ui/mutex_atomic.stderr
+++ b/tests/ui/mutex_atomic.stderr
@@ -1,4 +1,4 @@
-error: Consider using an `AtomicBool` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:6:5
    |
 LL |     Mutex::new(true);
@@ -6,31 +6,31 @@ LL |     Mutex::new(true);
    |
    = note: `-D clippy::mutex-atomic` implied by `-D warnings`
 
-error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:7:5
    |
 LL |     Mutex::new(5usize);
    |     ^^^^^^^^^^^^^^^^^^
 
-error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:8:5
    |
 LL |     Mutex::new(9isize);
    |     ^^^^^^^^^^^^^^^^^^
 
-error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:10:5
    |
 LL |     Mutex::new(&x as *const u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:11:5
    |
 LL |     Mutex::new(&mut x as *mut u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:12:5
    |
 LL |     Mutex::new(0u32);
@@ -38,7 +38,7 @@ LL |     Mutex::new(0u32);
    |
    = note: `-D clippy::mutex-integer` implied by `-D warnings`
 
-error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
+error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:13:5
    |
 LL |     Mutex::new(0i32);
diff --git a/tests/ui/needless_doc_main.rs b/tests/ui/needless_doc_main.rs
index 682d7b3c4ce..883683e08a2 100644
--- a/tests/ui/needless_doc_main.rs
+++ b/tests/ui/needless_doc_main.rs
@@ -9,8 +9,14 @@
 /// }
 /// ```
 ///
-/// This should, too.
+/// With an explicit return type it should lint too
+/// ```
+/// fn main() -> () {
+///     unimplemented!();
+/// }
+/// ```
 ///
+/// This should, too.
 /// ```rust
 /// fn main() {
 ///     unimplemented!();
@@ -18,7 +24,6 @@
 /// ```
 ///
 /// This one too.
-///
 /// ```no_run
 /// fn main() {
 ///     unimplemented!();
@@ -33,6 +38,20 @@ fn bad_doctests() {}
 /// fn main(){}
 /// ```
 ///
+/// This shouldn't lint either, because main is async:
+/// ```
+/// async fn main() {
+///     assert_eq!(42, ANSWER);
+/// }
+/// ```
+///
+/// Same here, because the return type is not the unit type:
+/// ```
+/// fn main() -> Result<()> {
+///     Ok(())
+/// }
+/// ```
+///
 /// This shouldn't lint either, because there's a `static`:
 /// ```
 /// static ANSWER: i32 = 42;
@@ -42,6 +61,15 @@ fn bad_doctests() {}
 /// }
 /// ```
 ///
+/// This shouldn't lint either, because there's a `const`:
+/// ```
+/// fn main() {
+///     assert_eq!(42, ANSWER);
+/// }
+///
+/// const ANSWER: i32 = 42;
+/// ```
+///
 /// Neither should this lint because of `extern crate`:
 /// ```
 /// #![feature(test)]
@@ -51,8 +79,41 @@ fn bad_doctests() {}
 /// }
 /// ```
 ///
-/// We should not lint ignored examples:
+/// Neither should this lint because it has an extern block:
+/// ```
+/// extern {}
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
+///
+/// This should not lint because there is another function defined:
+/// ```
+/// fn fun() {}
+///
+/// fn main() {
+///     unimplemented!();
+/// }
+/// ```
 ///
+/// We should not lint inside raw strings ...
+/// ```
+/// let string = r#"
+/// fn main() {
+///     unimplemented!();
+/// }
+/// "#;
+/// ```
+///
+/// ... or comments
+/// ```
+/// // fn main() {
+/// //     let _inception = 42;
+/// // }
+/// let _inception = 42;
+/// ```
+///
+/// We should not lint ignored examples:
 /// ```rust,ignore
 /// fn main() {
 ///     unimplemented!();
@@ -60,7 +121,6 @@ fn bad_doctests() {}
 /// ```
 ///
 /// Or even non-rust examples:
-///
 /// ```text
 /// fn main() {
 ///     is what starts the program
diff --git a/tests/ui/needless_doc_main.stderr b/tests/ui/needless_doc_main.stderr
index 65d40ee6832..05c7f9d33a7 100644
--- a/tests/ui/needless_doc_main.stderr
+++ b/tests/ui/needless_doc_main.stderr
@@ -7,16 +7,22 @@ LL | /// fn main() {
    = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:15:4
+  --> $DIR/needless_doc_main.rs:14:4
+   |
+LL | /// fn main() -> () {
+   |    ^^^^^^^^^^^^^^^^^^
+
+error: needless `fn main` in doctest
+  --> $DIR/needless_doc_main.rs:21:4
    |
 LL | /// fn main() {
    |    ^^^^^^^^^^^^
 
 error: needless `fn main` in doctest
-  --> $DIR/needless_doc_main.rs:23:4
+  --> $DIR/needless_doc_main.rs:28:4
    |
 LL | /// fn main() {
    |    ^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index ad20e238107..d849e093da7 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -69,6 +69,23 @@ fn test_void_match(x: u32) {
     }
 }
 
+fn read_line() -> String {
+    use std::io::BufRead;
+    let stdin = ::std::io::stdin();
+    return stdin.lock().lines().next().unwrap().unwrap();
+}
+
+fn borrows_but_not_last(value: bool) -> String {
+    if value {
+        use std::io::BufRead;
+        let stdin = ::std::io::stdin();
+        let _a = stdin.lock().lines().next().unwrap().unwrap();
+        String::from("test")
+    } else {
+        String::new()
+    }
+}
+
 fn main() {
     let _ = test_end_of_fn();
     let _ = test_no_semicolon();
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index af0cdfb207f..29f2bd1852a 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -69,6 +69,23 @@ fn test_void_match(x: u32) {
     }
 }
 
+fn read_line() -> String {
+    use std::io::BufRead;
+    let stdin = ::std::io::stdin();
+    return stdin.lock().lines().next().unwrap().unwrap();
+}
+
+fn borrows_but_not_last(value: bool) -> String {
+    if value {
+        use std::io::BufRead;
+        let stdin = ::std::io::stdin();
+        let _a = stdin.lock().lines().next().unwrap().unwrap();
+        return String::from("test");
+    } else {
+        return String::new();
+    }
+}
+
 fn main() {
     let _ = test_end_of_fn();
     let _ = test_no_semicolon();
diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr
index c34eecbcbb6..f73c833a801 100644
--- a/tests/ui/needless_return.stderr
+++ b/tests/ui/needless_return.stderr
@@ -72,5 +72,17 @@ error: unneeded `return` statement
 LL |         _ => return,
    |              ^^^^^^ help: replace `return` with an empty block: `{}`
 
-error: aborting due to 12 previous errors
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:83:9
+   |
+LL |         return String::from("test");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:85:9
+   |
+LL |         return String::new();
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed
index 4d284ae1319..163bd044c17 100644
--- a/tests/ui/precedence.fixed
+++ b/tests/ui/precedence.fixed
@@ -48,6 +48,14 @@ fn main() {
     let _ = -1f64.to_degrees();
     let _ = -1f64.to_radians();
 
+    // Chains containing any non-odd function should trigger (issue #5924)
+    let _ = -(1.0_f64.cos().cos());
+    let _ = -(1.0_f64.cos().sin());
+    let _ = -(1.0_f64.sin().cos());
+
+    // Chains of odd functions shouldn't trigger
+    let _ = -1f64.sin().sin();
+
     let b = 3;
     trip!(b * 8);
 }
diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs
index 2d08e82f349..8c849e3209b 100644
--- a/tests/ui/precedence.rs
+++ b/tests/ui/precedence.rs
@@ -48,6 +48,14 @@ fn main() {
     let _ = -1f64.to_degrees();
     let _ = -1f64.to_radians();
 
+    // Chains containing any non-odd function should trigger (issue #5924)
+    let _ = -1.0_f64.cos().cos();
+    let _ = -1.0_f64.cos().sin();
+    let _ = -1.0_f64.sin().cos();
+
+    // Chains of odd functions shouldn't trigger
+    let _ = -1f64.sin().sin();
+
     let b = 3;
     trip!(b * 8);
 }
diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr
index a2ed5392bfc..03d585b3975 100644
--- a/tests/ui/precedence.stderr
+++ b/tests/ui/precedence.stderr
@@ -54,5 +54,23 @@ error: unary minus has lower precedence than method call
 LL |     -1f32.abs();
    |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())`
 
-error: aborting due to 9 previous errors
+error: unary minus has lower precedence than method call
+  --> $DIR/precedence.rs:52:13
+   |
+LL |     let _ = -1.0_f64.cos().cos();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())`
+
+error: unary minus has lower precedence than method call
+  --> $DIR/precedence.rs:53:13
+   |
+LL |     let _ = -1.0_f64.cos().sin();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())`
+
+error: unary minus has lower precedence than method call
+  --> $DIR/precedence.rs:54:13
+   |
+LL |     let _ = -1.0_f64.sin().cos();
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())`
+
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/redundant_allocation.fixed b/tests/ui/redundant_allocation.fixed
index 26635833458..6514fd6d1ac 100644
--- a/tests/ui/redundant_allocation.fixed
+++ b/tests/ui/redundant_allocation.fixed
@@ -33,7 +33,7 @@ pub fn test5(a: Rc<bool>) {}
 
 // Rc<Box<T>>
 
-pub fn test6(a: Box<bool>) {}
+pub fn test6(a: Rc<bool>) {}
 
 // Box<&T>
 
diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr
index eaa57ce3024..92e4f67f5db 100644
--- a/tests/ui/redundant_allocation.stderr
+++ b/tests/ui/redundant_allocation.stderr
@@ -28,7 +28,7 @@ error: usage of `Rc<Box<T>>`
   --> $DIR/redundant_allocation.rs:36:17
    |
 LL | pub fn test6(a: Rc<Box<bool>>) {}
-   |                 ^^^^^^^^^^^^^ help: try: `Box<bool>`
+   |                 ^^^^^^^^^^^^^ help: try: `Rc<bool>`
 
 error: usage of `Box<&T>`
   --> $DIR/redundant_allocation.rs:40:22
diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs
index ff1088f86f6..bfe27e02044 100644
--- a/tests/ui/same_item_push.rs
+++ b/tests/ui/same_item_push.rs
@@ -86,4 +86,12 @@ fn main() {
     for a in vec_a {
         vec12.push(2u8.pow(a.kind));
     }
+
+    // Fix #5902
+    let mut vec13: Vec<u8> = Vec::new();
+    let mut item = 0;
+    for _ in 0..10 {
+        vec13.push(item);
+        item += 10;
+    }
 }
diff --git a/tests/ui/self_assignment.rs b/tests/ui/self_assignment.rs
new file mode 100644
index 00000000000..a7cbb9cd78b
--- /dev/null
+++ b/tests/ui/self_assignment.rs
@@ -0,0 +1,67 @@
+#![warn(clippy::self_assignment)]
+
+pub struct S<'a> {
+    a: i32,
+    b: [i32; 10],
+    c: Vec<Vec<i32>>,
+    e: &'a mut i32,
+    f: &'a mut i32,
+}
+
+pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
+    a = a;
+    *b = *b;
+    s = s;
+    s.a = s.a;
+    s.b[10] = s.b[5 + 5];
+    s.c[0][1] = s.c[0][1];
+    s.b[a] = s.b[a];
+    *s.e = *s.e;
+    s.b[a + 10] = s.b[10 + a];
+
+    let mut t = (0, 1);
+    t.1 = t.1;
+    t.0 = (t.0);
+}
+
+pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) {
+    dbg!(&a);
+    a = *b;
+    dbg!(&a);
+    s.b[1] += s.b[1];
+    s.b[1] = s.b[2];
+    s.c[1][0] = s.c[0][1];
+    s.b[a] = s.b[*b];
+    s.b[a + 10] = s.b[a + 11];
+    *s.e = *s.f;
+
+    let mut t = (0, 1);
+    t.0 = t.1;
+}
+
+#[allow(clippy::eval_order_dependence)]
+pub fn negatives_side_effects() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    let mut i = 0;
+    v[{
+        i += 1;
+        i
+    }] = v[{
+        i += 1;
+        i
+    }];
+
+    fn next(n: &mut usize) -> usize {
+        let v = *n;
+        *n += 1;
+        v
+    }
+
+    let mut w = vec![1, 2, 3, 4, 5];
+    let mut i = 0;
+    let i = &mut i;
+    w[next(i)] = w[next(i)];
+    w[next(i)] = w[next(i)];
+}
+
+fn main() {}
diff --git a/tests/ui/self_assignment.stderr b/tests/ui/self_assignment.stderr
new file mode 100644
index 00000000000..826e0d0ba88
--- /dev/null
+++ b/tests/ui/self_assignment.stderr
@@ -0,0 +1,70 @@
+error: self-assignment of `a` to `a`
+  --> $DIR/self_assignment.rs:12:5
+   |
+LL |     a = a;
+   |     ^^^^^
+   |
+   = note: `-D clippy::self-assignment` implied by `-D warnings`
+
+error: self-assignment of `*b` to `*b`
+  --> $DIR/self_assignment.rs:13:5
+   |
+LL |     *b = *b;
+   |     ^^^^^^^
+
+error: self-assignment of `s` to `s`
+  --> $DIR/self_assignment.rs:14:5
+   |
+LL |     s = s;
+   |     ^^^^^
+
+error: self-assignment of `s.a` to `s.a`
+  --> $DIR/self_assignment.rs:15:5
+   |
+LL |     s.a = s.a;
+   |     ^^^^^^^^^
+
+error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
+  --> $DIR/self_assignment.rs:16:5
+   |
+LL |     s.b[10] = s.b[5 + 5];
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
+  --> $DIR/self_assignment.rs:17:5
+   |
+LL |     s.c[0][1] = s.c[0][1];
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: self-assignment of `s.b[a]` to `s.b[a]`
+  --> $DIR/self_assignment.rs:18:5
+   |
+LL |     s.b[a] = s.b[a];
+   |     ^^^^^^^^^^^^^^^
+
+error: self-assignment of `*s.e` to `*s.e`
+  --> $DIR/self_assignment.rs:19:5
+   |
+LL |     *s.e = *s.e;
+   |     ^^^^^^^^^^^
+
+error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]`
+  --> $DIR/self_assignment.rs:20:5
+   |
+LL |     s.b[a + 10] = s.b[10 + a];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: self-assignment of `t.1` to `t.1`
+  --> $DIR/self_assignment.rs:23:5
+   |
+LL |     t.1 = t.1;
+   |     ^^^^^^^^^
+
+error: self-assignment of `(t.0)` to `t.0`
+  --> $DIR/self_assignment.rs:24:5
+   |
+LL |     t.0 = (t.0);
+   |     ^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs
new file mode 100644
index 00000000000..6c5ffe6aba8
--- /dev/null
+++ b/tests/ui/should_impl_trait/corner_cases.rs
@@ -0,0 +1,83 @@
+// edition:2018
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(
+    clippy::missing_errors_doc,
+    clippy::needless_pass_by_value,
+    clippy::must_use_candidate,
+    clippy::unused_self,
+    clippy::needless_lifetimes,
+    clippy::missing_safety_doc,
+    clippy::wrong_self_convention
+)]
+
+use std::ops::Mul;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+
+pub struct T1;
+impl T1 {
+    // corner cases: should not lint
+
+    // no error, not public interface
+    pub(crate) fn drop(&mut self) {}
+
+    // no error, private function
+    fn neg(self) -> Self {
+        self
+    }
+
+    // no error, private function
+    fn eq(&self, other: Self) -> bool {
+        true
+    }
+
+    // No error; self is a ref.
+    fn sub(&self, other: Self) -> &Self {
+        self
+    }
+
+    // No error; different number of arguments.
+    fn div(self) -> Self {
+        self
+    }
+
+    // No error; wrong return type.
+    fn rem(self, other: Self) {}
+
+    // Fine
+    fn into_u32(self) -> u32 {
+        0
+    }
+
+    fn into_u16(&self) -> u16 {
+        0
+    }
+
+    fn to_something(self) -> u32 {
+        0
+    }
+
+    fn new(self) -> Self {
+        unimplemented!();
+    }
+
+    pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> {
+        unimplemented!();
+    }
+}
+
+pub struct T2;
+impl T2 {
+    // Shouldn't trigger lint as it is unsafe.
+    pub unsafe fn add(self, rhs: Self) -> Self {
+        self
+    }
+
+    // Should not trigger lint since this is an async function.
+    pub async fn next(&mut self) -> Option<Self> {
+        None
+    }
+}
diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs
new file mode 100644
index 00000000000..f8d248fc98d
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_1.rs
@@ -0,0 +1,87 @@
+// edition:2018
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(
+    clippy::missing_errors_doc,
+    clippy::needless_pass_by_value,
+    clippy::must_use_candidate,
+    clippy::unused_self,
+    clippy::needless_lifetimes,
+    clippy::missing_safety_doc,
+    clippy::wrong_self_convention
+)]
+
+use std::ops::Mul;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+pub struct T;
+
+impl T {
+    // *****************************************
+    // trait method list part 1, should lint all
+    // *****************************************
+    pub fn add(self, other: T) -> T {
+        unimplemented!()
+    }
+
+    pub fn as_mut(&mut self) -> &mut T {
+        unimplemented!()
+    }
+
+    pub fn as_ref(&self) -> &T {
+        unimplemented!()
+    }
+
+    pub fn bitand(self, rhs: T) -> T {
+        unimplemented!()
+    }
+
+    pub fn bitor(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn bitxor(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn borrow(&self) -> &str {
+        unimplemented!()
+    }
+
+    pub fn borrow_mut(&mut self) -> &mut str {
+        unimplemented!()
+    }
+
+    pub fn clone(&self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn cmp(&self, other: &Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn default() -> Self {
+        unimplemented!()
+    }
+
+    pub fn deref(&self) -> &Self {
+        unimplemented!()
+    }
+
+    pub fn deref_mut(&mut self) -> &mut Self {
+        unimplemented!()
+    }
+
+    pub fn div(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn drop(&mut self) {
+        unimplemented!()
+    }
+    // **********
+    // part 1 end
+    // **********
+}
diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr
new file mode 100644
index 00000000000..2b7d4628c3f
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_1.stderr
@@ -0,0 +1,143 @@
+error: method `add` can be confused for the standard trait method `std::ops::Add::add`
+  --> $DIR/method_list_1.rs:25:5
+   |
+LL | /     pub fn add(self, other: T) -> T {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
+   = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
+
+error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
+  --> $DIR/method_list_1.rs:29:5
+   |
+LL | /     pub fn as_mut(&mut self) -> &mut T {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
+
+error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
+  --> $DIR/method_list_1.rs:33:5
+   |
+LL | /     pub fn as_ref(&self) -> &T {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
+
+error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
+  --> $DIR/method_list_1.rs:37:5
+   |
+LL | /     pub fn bitand(self, rhs: T) -> T {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
+
+error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
+  --> $DIR/method_list_1.rs:41:5
+   |
+LL | /     pub fn bitor(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
+
+error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
+  --> $DIR/method_list_1.rs:45:5
+   |
+LL | /     pub fn bitxor(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
+
+error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
+  --> $DIR/method_list_1.rs:49:5
+   |
+LL | /     pub fn borrow(&self) -> &str {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
+
+error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
+  --> $DIR/method_list_1.rs:53:5
+   |
+LL | /     pub fn borrow_mut(&mut self) -> &mut str {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
+
+error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
+  --> $DIR/method_list_1.rs:57:5
+   |
+LL | /     pub fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
+
+error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
+  --> $DIR/method_list_1.rs:61:5
+   |
+LL | /     pub fn cmp(&self, other: &Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
+
+error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
+  --> $DIR/method_list_1.rs:69:5
+   |
+LL | /     pub fn deref(&self) -> &Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
+
+error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
+  --> $DIR/method_list_1.rs:73:5
+   |
+LL | /     pub fn deref_mut(&mut self) -> &mut Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
+
+error: method `div` can be confused for the standard trait method `std::ops::Div::div`
+  --> $DIR/method_list_1.rs:77:5
+   |
+LL | /     pub fn div(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
+
+error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
+  --> $DIR/method_list_1.rs:81:5
+   |
+LL | /     pub fn drop(&mut self) {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
+
+error: aborting due to 14 previous errors
+
diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs
new file mode 100644
index 00000000000..ed5e0d384bf
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_2.rs
@@ -0,0 +1,88 @@
+// edition:2018
+
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(
+    clippy::missing_errors_doc,
+    clippy::needless_pass_by_value,
+    clippy::must_use_candidate,
+    clippy::unused_self,
+    clippy::needless_lifetimes,
+    clippy::missing_safety_doc,
+    clippy::wrong_self_convention
+)]
+
+use std::ops::Mul;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+pub struct T;
+
+impl T {
+    // *****************************************
+    // trait method list part 2, should lint all
+    // *****************************************
+
+    pub fn eq(&self, other: &Self) -> bool {
+        unimplemented!()
+    }
+
+    pub fn from_iter<T>(iter: T) -> Self {
+        unimplemented!()
+    }
+
+    pub fn from_str(s: &str) -> Result<Self, Self> {
+        unimplemented!()
+    }
+
+    pub fn hash(&self, state: &mut T) {
+        unimplemented!()
+    }
+
+    pub fn index(&self, index: usize) -> &Self {
+        unimplemented!()
+    }
+
+    pub fn index_mut(&mut self, index: usize) -> &mut Self {
+        unimplemented!()
+    }
+
+    pub fn into_iter(self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn mul(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn neg(self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn next(&mut self) -> Option<Self> {
+        unimplemented!()
+    }
+
+    pub fn not(self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn rem(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn shl(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn shr(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+
+    pub fn sub(self, rhs: Self) -> Self {
+        unimplemented!()
+    }
+    // **********
+    // part 2 end
+    // **********
+}
diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr
new file mode 100644
index 00000000000..b6fd4356956
--- /dev/null
+++ b/tests/ui/should_impl_trait/method_list_2.stderr
@@ -0,0 +1,153 @@
+error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
+  --> $DIR/method_list_2.rs:26:5
+   |
+LL | /     pub fn eq(&self, other: &Self) -> bool {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
+   = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
+
+error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
+  --> $DIR/method_list_2.rs:30:5
+   |
+LL | /     pub fn from_iter<T>(iter: T) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
+
+error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
+  --> $DIR/method_list_2.rs:34:5
+   |
+LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
+
+error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
+  --> $DIR/method_list_2.rs:38:5
+   |
+LL | /     pub fn hash(&self, state: &mut T) {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
+
+error: method `index` can be confused for the standard trait method `std::ops::Index::index`
+  --> $DIR/method_list_2.rs:42:5
+   |
+LL | /     pub fn index(&self, index: usize) -> &Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
+
+error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
+  --> $DIR/method_list_2.rs:46:5
+   |
+LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
+
+error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
+  --> $DIR/method_list_2.rs:50:5
+   |
+LL | /     pub fn into_iter(self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
+
+error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
+  --> $DIR/method_list_2.rs:54:5
+   |
+LL | /     pub fn mul(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
+
+error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
+  --> $DIR/method_list_2.rs:58:5
+   |
+LL | /     pub fn neg(self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
+
+error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
+  --> $DIR/method_list_2.rs:62:5
+   |
+LL | /     pub fn next(&mut self) -> Option<Self> {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
+
+error: method `not` can be confused for the standard trait method `std::ops::Not::not`
+  --> $DIR/method_list_2.rs:66:5
+   |
+LL | /     pub fn not(self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
+
+error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
+  --> $DIR/method_list_2.rs:70:5
+   |
+LL | /     pub fn rem(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
+
+error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
+  --> $DIR/method_list_2.rs:74:5
+   |
+LL | /     pub fn shl(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
+
+error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
+  --> $DIR/method_list_2.rs:78:5
+   |
+LL | /     pub fn shr(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
+
+error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
+  --> $DIR/method_list_2.rs:82:5
+   |
+LL | /     pub fn sub(self, rhs: Self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
+   |
+   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed
new file mode 100644
index 00000000000..0812c026a64
--- /dev/null
+++ b/tests/ui/single_char_push_str.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+#![warn(clippy::single_char_push_str)]
+
+fn main() {
+    let mut string = String::new();
+    string.push('R');
+    string.push('\'');
+
+    string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push('\x52');
+    string.push('\u{0052}');
+    string.push('a');
+}
diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs
new file mode 100644
index 00000000000..ab293bbe4ee
--- /dev/null
+++ b/tests/ui/single_char_push_str.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+#![warn(clippy::single_char_push_str)]
+
+fn main() {
+    let mut string = String::new();
+    string.push_str("R");
+    string.push_str("'");
+
+    string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push_str("\x52");
+    string.push_str("\u{0052}");
+    string.push_str(r##"a"##);
+}
diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr
new file mode 100644
index 00000000000..0e9bdaa23e7
--- /dev/null
+++ b/tests/ui/single_char_push_str.stderr
@@ -0,0 +1,34 @@
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:6:5
+   |
+LL |     string.push_str("R");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')`
+   |
+   = note: `-D clippy::single-char-push-str` implied by `-D warnings`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:7:5
+   |
+LL |     string.push_str("'");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:12:5
+   |
+LL |     string.push_str("/x52");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:13:5
+   |
+LL |     string.push_str("/u{0052}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:14:5
+   |
+LL |     string.push_str(r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/stable_sort_primitive.stderr b/tests/ui/stable_sort_primitive.stderr
index b0b729ede48..b73012a4691 100644
--- a/tests/ui/stable_sort_primitive.stderr
+++ b/tests/ui/stable_sort_primitive.stderr
@@ -1,4 +1,4 @@
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:7:5
    |
 LL |     vec.sort();
@@ -6,37 +6,37 @@ LL |     vec.sort();
    |
    = note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:9:5
    |
 LL |     vec.sort();
    |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:11:5
    |
 LL |     vec.sort();
    |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:13:5
    |
 LL |     vec.sort();
    |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:15:5
    |
 LL |     vec.sort();
    |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:17:5
    |
 LL |     vec.sort();
    |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
-error: Use sort_unstable instead of sort
+error: used sort instead of sort_unstable
   --> $DIR/stable_sort_primitive.rs:19:5
    |
 LL |     arr.sort();
diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs
index 60c2f3ec9b6..5c280efac1a 100644
--- a/tests/ui/suspicious_arithmetic_impl.rs
+++ b/tests/ui/suspicious_arithmetic_impl.rs
@@ -1,5 +1,7 @@
 #![warn(clippy::suspicious_arithmetic_impl)]
-use std::ops::{Add, AddAssign, BitOrAssign, Div, DivAssign, Mul, MulAssign, Sub};
+use std::ops::{
+    Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub,
+};
 
 #[derive(Copy, Clone)]
 struct Foo(u32);
@@ -61,6 +63,54 @@ impl Div for Foo {
     }
 }
 
+impl Rem for Foo {
+    type Output = Foo;
+
+    fn rem(self, other: Self) -> Self {
+        Foo(self.0 / other.0)
+    }
+}
+
+impl BitAnd for Foo {
+    type Output = Foo;
+
+    fn bitand(self, other: Self) -> Self {
+        Foo(self.0 | other.0)
+    }
+}
+
+impl BitOr for Foo {
+    type Output = Foo;
+
+    fn bitor(self, other: Self) -> Self {
+        Foo(self.0 ^ other.0)
+    }
+}
+
+impl BitXor for Foo {
+    type Output = Foo;
+
+    fn bitxor(self, other: Self) -> Self {
+        Foo(self.0 & other.0)
+    }
+}
+
+impl Shl for Foo {
+    type Output = Foo;
+
+    fn shl(self, other: Self) -> Self {
+        Foo(self.0 >> other.0)
+    }
+}
+
+impl Shr for Foo {
+    type Output = Foo;
+
+    fn shr(self, other: Self) -> Self {
+        Foo(self.0 << other.0)
+    }
+}
+
 struct Bar(i32);
 
 impl Add for Bar {
diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr
index 23d47e3f1ff..388fc740082 100644
--- a/tests/ui/suspicious_arithmetic_impl.stderr
+++ b/tests/ui/suspicious_arithmetic_impl.stderr
@@ -1,5 +1,5 @@
 error: suspicious use of binary operator in `Add` impl
-  --> $DIR/suspicious_arithmetic_impl.rs:11:20
+  --> $DIR/suspicious_arithmetic_impl.rs:13:20
    |
 LL |         Foo(self.0 - other.0)
    |                    ^
@@ -7,7 +7,7 @@ LL |         Foo(self.0 - other.0)
    = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings`
 
 error: suspicious use of binary operator in `AddAssign` impl
-  --> $DIR/suspicious_arithmetic_impl.rs:17:23
+  --> $DIR/suspicious_arithmetic_impl.rs:19:23
    |
 LL |         *self = *self - other;
    |                       ^
@@ -15,10 +15,46 @@ LL |         *self = *self - other;
    = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default
 
 error: suspicious use of binary operator in `MulAssign` impl
-  --> $DIR/suspicious_arithmetic_impl.rs:30:16
+  --> $DIR/suspicious_arithmetic_impl.rs:32:16
    |
 LL |         self.0 /= other.0;
    |                ^^
 
-error: aborting due to 3 previous errors
+error: suspicious use of binary operator in `Rem` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:70:20
+   |
+LL |         Foo(self.0 / other.0)
+   |                    ^
+
+error: suspicious use of binary operator in `BitAnd` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:78:20
+   |
+LL |         Foo(self.0 | other.0)
+   |                    ^
+
+error: suspicious use of binary operator in `BitOr` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:86:20
+   |
+LL |         Foo(self.0 ^ other.0)
+   |                    ^
+
+error: suspicious use of binary operator in `BitXor` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:94:20
+   |
+LL |         Foo(self.0 & other.0)
+   |                    ^
+
+error: suspicious use of binary operator in `Shl` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:102:20
+   |
+LL |         Foo(self.0 >> other.0)
+   |                    ^^
+
+error: suspicious use of binary operator in `Shr` impl
+  --> $DIR/suspicious_arithmetic_impl.rs:110:20
+   |
+LL |         Foo(self.0 << other.0)
+   |                    ^^
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/to_string_in_display.rs b/tests/ui/to_string_in_display.rs
new file mode 100644
index 00000000000..3b46324704e
--- /dev/null
+++ b/tests/ui/to_string_in_display.rs
@@ -0,0 +1,55 @@
+#![warn(clippy::to_string_in_display)]
+#![allow(clippy::inherent_to_string_shadow_display)]
+
+use std::fmt;
+
+struct A;
+impl A {
+    fn fmt(&self) {
+        self.to_string();
+    }
+}
+
+trait B {
+    fn fmt(&self) {}
+}
+
+impl B for A {
+    fn fmt(&self) {
+        self.to_string();
+    }
+}
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_string())
+    }
+}
+
+fn fmt(a: A) {
+    a.to_string();
+}
+
+struct C;
+
+impl C {
+    fn to_string(&self) -> String {
+        String::from("I am C")
+    }
+}
+
+impl fmt::Display for C {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_string())
+    }
+}
+
+fn main() {
+    let a = A;
+    a.to_string();
+    a.fmt();
+    fmt(a);
+
+    let c = C;
+    c.to_string();
+}
diff --git a/tests/ui/to_string_in_display.stderr b/tests/ui/to_string_in_display.stderr
new file mode 100644
index 00000000000..cbc0a41036b
--- /dev/null
+++ b/tests/ui/to_string_in_display.stderr
@@ -0,0 +1,10 @@
+error: Using to_string in fmt::Display implementation might lead to infinite recursion
+  --> $DIR/to_string_in_display.rs:25:25
+   |
+LL |         write!(f, "{}", self.to_string())
+   |                         ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::to-string-in-display` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs
index bb853d23704..9f1948359e7 100644
--- a/tests/ui/transmute.rs
+++ b/tests/ui/transmute.rs
@@ -1,3 +1,4 @@
+#![feature(const_fn_transmute)]
 #![allow(dead_code)]
 
 extern crate core;
@@ -81,9 +82,26 @@ fn int_to_bool() {
 }
 
 #[warn(clippy::transmute_int_to_float)]
-fn int_to_float() {
-    let _: f32 = unsafe { std::mem::transmute(0_u32) };
-    let _: f32 = unsafe { std::mem::transmute(0_i32) };
+mod int_to_float {
+    fn test() {
+        let _: f32 = unsafe { std::mem::transmute(0_u32) };
+        let _: f32 = unsafe { std::mem::transmute(0_i32) };
+        let _: f64 = unsafe { std::mem::transmute(0_u64) };
+        let _: f64 = unsafe { std::mem::transmute(0_i64) };
+    }
+
+    mod issue_5747 {
+        const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
+        const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
+
+        const fn from_bits_32(v: i32) -> f32 {
+            unsafe { std::mem::transmute(v) }
+        }
+
+        const fn from_bits_64(v: u64) -> f64 {
+            unsafe { std::mem::transmute(v) }
+        }
+    }
 }
 
 fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr
index 8582080498f..ad9953d12bc 100644
--- a/tests/ui/transmute.stderr
+++ b/tests/ui/transmute.stderr
@@ -1,5 +1,5 @@
 error: transmute from a type (`&T`) to itself
-  --> $DIR/transmute.rs:19:20
+  --> $DIR/transmute.rs:20:20
    |
 LL |     let _: &'a T = core::intrinsics::transmute(t);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,67 +7,67 @@ LL |     let _: &'a T = core::intrinsics::transmute(t);
    = note: `-D clippy::useless-transmute` implied by `-D warnings`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:23:23
+  --> $DIR/transmute.rs:24:23
    |
 LL |     let _: *const T = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:25:21
+  --> $DIR/transmute.rs:26:21
    |
 LL |     let _: *mut T = core::intrinsics::transmute(t);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:27:23
+  --> $DIR/transmute.rs:28:23
    |
 LL |     let _: *const U = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:33:27
+  --> $DIR/transmute.rs:34:27
    |
 LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:35:27
+  --> $DIR/transmute.rs:36:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:37:27
+  --> $DIR/transmute.rs:38:27
    |
 LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:39:27
+  --> $DIR/transmute.rs:40:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:41:27
+  --> $DIR/transmute.rs:42:27
    |
 LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:43:31
+  --> $DIR/transmute.rs:44:31
    |
 LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:47:31
+  --> $DIR/transmute.rs:48:31
    |
 LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-  --> $DIR/transmute.rs:62:24
+  --> $DIR/transmute.rs:63:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,25 +75,25 @@ LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-  --> $DIR/transmute.rs:64:24
+  --> $DIR/transmute.rs:65:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-  --> $DIR/transmute.rs:66:31
+  --> $DIR/transmute.rs:67:31
    |
 LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-  --> $DIR/transmute.rs:68:29
+  --> $DIR/transmute.rs:69:29
    |
 LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u32` to a `char`
-  --> $DIR/transmute.rs:74:28
+  --> $DIR/transmute.rs:75:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
@@ -101,13 +101,13 @@ LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
    = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
 
 error: transmute from a `i32` to a `char`
-  --> $DIR/transmute.rs:75:28
+  --> $DIR/transmute.rs:76:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
 
 error: transmute from a `u8` to a `bool`
-  --> $DIR/transmute.rs:80:28
+  --> $DIR/transmute.rs:81:28
    |
 LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -115,21 +115,33 @@ LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
 
 error: transmute from a `u32` to a `f32`
-  --> $DIR/transmute.rs:85:27
+  --> $DIR/transmute.rs:87:31
    |
-LL |     let _: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
+LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
    |
    = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
 
 error: transmute from a `i32` to a `f32`
-  --> $DIR/transmute.rs:86:27
+  --> $DIR/transmute.rs:88:31
+   |
+LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
+
+error: transmute from a `u64` to a `f64`
+  --> $DIR/transmute.rs:89:31
+   |
+LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
+
+error: transmute from a `i64` to a `f64`
+  --> $DIR/transmute.rs:90:31
    |
-LL |     let _: f32 = unsafe { std::mem::transmute(0_i32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
+LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> $DIR/transmute.rs:90:28
+  --> $DIR/transmute.rs:108:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(b) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
@@ -137,10 +149,10 @@ LL |     let _: &str = unsafe { std::mem::transmute(b) };
    = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> $DIR/transmute.rs:91:32
+  --> $DIR/transmute.rs:109:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
-error: aborting due to 22 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs
index ce942751ada..1040fee4b34 100644
--- a/tests/ui/transmute_float_to_int.rs
+++ b/tests/ui/transmute_float_to_int.rs
@@ -1,4 +1,5 @@
-#[warn(clippy::transmute_float_to_int)]
+#![feature(const_fn_transmute)]
+#![warn(clippy::transmute_float_to_int)]
 
 fn float_to_int() {
     let _: u32 = unsafe { std::mem::transmute(1f32) };
@@ -9,4 +10,17 @@ fn float_to_int() {
     let _: u64 = unsafe { std::mem::transmute(-1.0) };
 }
 
+mod issue_5747 {
+    const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
+    const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
+
+    const fn to_bits_32(v: f32) -> u32 {
+        unsafe { std::mem::transmute(v) }
+    }
+
+    const fn to_bits_64(v: f64) -> i64 {
+        unsafe { std::mem::transmute(v) }
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/transmute_float_to_int.stderr b/tests/ui/transmute_float_to_int.stderr
index eb786bb39f9..5a40cf381d6 100644
--- a/tests/ui/transmute_float_to_int.stderr
+++ b/tests/ui/transmute_float_to_int.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `f32` to a `u32`
-  --> $DIR/transmute_float_to_int.rs:4:27
+  --> $DIR/transmute_float_to_int.rs:5:27
    |
 LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
@@ -7,31 +7,31 @@ LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
    = note: `-D clippy::transmute-float-to-int` implied by `-D warnings`
 
 error: transmute from a `f32` to a `i32`
-  --> $DIR/transmute_float_to_int.rs:5:27
+  --> $DIR/transmute_float_to_int.rs:6:27
    |
 LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
 
 error: transmute from a `f64` to a `u64`
-  --> $DIR/transmute_float_to_int.rs:6:27
+  --> $DIR/transmute_float_to_int.rs:7:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
 
 error: transmute from a `f64` to a `i64`
-  --> $DIR/transmute_float_to_int.rs:7:27
+  --> $DIR/transmute_float_to_int.rs:8:27
    |
 LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
 
 error: transmute from a `f64` to a `u64`
-  --> $DIR/transmute_float_to_int.rs:8:27
+  --> $DIR/transmute_float_to_int.rs:9:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
 
 error: transmute from a `f64` to a `u64`
-  --> $DIR/transmute_float_to_int.rs:9:27
+  --> $DIR/transmute_float_to_int.rs:10:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed
new file mode 100644
index 00000000000..fa66e68794e
--- /dev/null
+++ b/tests/ui/unnecessary_lazy_eval.fixed
@@ -0,0 +1,117 @@
+// run-rustfix
+#![warn(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::redundant_closure)]
+#![allow(clippy::bind_instead_of_map)]
+
+struct Deep(Option<usize>);
+
+#[derive(Copy, Clone)]
+struct SomeStruct {
+    some_field: usize,
+}
+
+impl SomeStruct {
+    fn return_some_field(&self) -> usize {
+        self.some_field
+    }
+}
+
+fn some_call<T: Default>() -> T {
+    T::default()
+}
+
+fn main() {
+    let astronomers_pi = 10;
+    let ext_arr: [usize; 1] = [2];
+    let ext_str = SomeStruct { some_field: 10 };
+
+    let mut opt = Some(42);
+    let ext_opt = Some(42);
+    let nested_opt = Some(Some(42));
+    let nested_tuple_opt = Some(Some((42, 43)));
+
+    // Should lint - Option
+    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.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]);
+
+    // Cases when unwrap is not called on a simple variable
+    let _ = Some(10).unwrap_or(2);
+    let _ = Some(10).and(ext_opt);
+    let _: Option<usize> = None.or(ext_opt);
+    let _ = None.get_or_insert(2);
+    let _: Result<usize, usize> = None.ok_or(2);
+    let _: Option<usize> = None.or(None);
+
+    let mut deep = Deep(Some(42));
+    let _ = deep.0.unwrap_or(2);
+    let _ = deep.0.and(ext_opt);
+    let _ = deep.0.or(None);
+    let _ = deep.0.get_or_insert(2);
+    let _ = deep.0.ok_or(2);
+
+    // 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());
+    let _: Result<usize, usize> = opt.ok_or_else(|| some_call());
+    let _: Result<usize, usize> = opt.ok_or_else(some_call);
+    let _ = deep.0.get_or_insert_with(|| some_call());
+    let _ = deep.0.or_else(some_call);
+    let _ = deep.0.or_else(|| some_call());
+
+    // These are handled by bind_instead_of_map
+    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 - Result
+    let res: Result<usize, usize> = Err(5);
+    let res2: Result<usize, SomeStruct> = Err(SomeStruct { some_field: 5 });
+
+    let _ = res2.unwrap_or(2);
+    let _ = res2.unwrap_or(astronomers_pi);
+    let _ = res2.unwrap_or(ext_str.some_field);
+
+    // Should not lint - Result
+    let _ = res.unwrap_or_else(|err| err);
+    let _ = res.unwrap_or_else(|err| ext_arr[err]);
+    let _ = res2.unwrap_or_else(|err| err.some_field);
+    let _ = res2.unwrap_or_else(|err| err.return_some_field());
+    let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
+
+    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));
+}
diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs
new file mode 100644
index 00000000000..04f47d1aa29
--- /dev/null
+++ b/tests/ui/unnecessary_lazy_eval.rs
@@ -0,0 +1,117 @@
+// run-rustfix
+#![warn(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::redundant_closure)]
+#![allow(clippy::bind_instead_of_map)]
+
+struct Deep(Option<usize>);
+
+#[derive(Copy, Clone)]
+struct SomeStruct {
+    some_field: usize,
+}
+
+impl SomeStruct {
+    fn return_some_field(&self) -> usize {
+        self.some_field
+    }
+}
+
+fn some_call<T: Default>() -> T {
+    T::default()
+}
+
+fn main() {
+    let astronomers_pi = 10;
+    let ext_arr: [usize; 1] = [2];
+    let ext_str = SomeStruct { some_field: 10 };
+
+    let mut opt = Some(42);
+    let ext_opt = Some(42);
+    let nested_opt = Some(Some(42));
+    let nested_tuple_opt = Some(Some((42, 43)));
+
+    // Should lint - Option
+    let _ = opt.unwrap_or_else(|| 2);
+    let _ = opt.unwrap_or_else(|| astronomers_pi);
+    let _ = opt.unwrap_or_else(|| ext_str.some_field);
+    let _ = opt.unwrap_or_else(|| ext_arr[0]);
+    let _ = opt.and_then(|_| ext_opt);
+    let _ = opt.or_else(|| ext_opt);
+    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]);
+
+    // Cases when unwrap is not called on a simple variable
+    let _ = Some(10).unwrap_or_else(|| 2);
+    let _ = Some(10).and_then(|_| ext_opt);
+    let _: Option<usize> = None.or_else(|| ext_opt);
+    let _ = None.get_or_insert_with(|| 2);
+    let _: Result<usize, usize> = None.ok_or_else(|| 2);
+    let _: Option<usize> = None.or_else(|| None);
+
+    let mut deep = Deep(Some(42));
+    let _ = deep.0.unwrap_or_else(|| 2);
+    let _ = deep.0.and_then(|_| ext_opt);
+    let _ = deep.0.or_else(|| None);
+    let _ = deep.0.get_or_insert_with(|| 2);
+    let _ = deep.0.ok_or_else(|| 2);
+
+    // 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());
+    let _: Result<usize, usize> = opt.ok_or_else(|| some_call());
+    let _: Result<usize, usize> = opt.ok_or_else(some_call);
+    let _ = deep.0.get_or_insert_with(|| some_call());
+    let _ = deep.0.or_else(some_call);
+    let _ = deep.0.or_else(|| some_call());
+
+    // These are handled by bind_instead_of_map
+    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 - Result
+    let res: Result<usize, usize> = Err(5);
+    let res2: Result<usize, SomeStruct> = Err(SomeStruct { some_field: 5 });
+
+    let _ = res2.unwrap_or_else(|_| 2);
+    let _ = res2.unwrap_or_else(|_| astronomers_pi);
+    let _ = res2.unwrap_or_else(|_| ext_str.some_field);
+
+    // Should not lint - Result
+    let _ = res.unwrap_or_else(|err| err);
+    let _ = res.unwrap_or_else(|err| ext_arr[err]);
+    let _ = res2.unwrap_or_else(|err| err.some_field);
+    let _ = res2.unwrap_or_else(|err| err.return_some_field());
+    let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
+
+    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));
+}
diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr
new file mode 100644
index 00000000000..5c1b2eb1f14
--- /dev/null
+++ b/tests/ui/unnecessary_lazy_eval.stderr
@@ -0,0 +1,148 @@
+error: unnecessary closure used to substitute value for `Option::None`
+  --> $DIR/unnecessary_lazy_eval.rs:34:13
+   |
+LL |     let _ = opt.unwrap_or_else(|| 2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+LL |     let _ = opt.ok_or_else(|| ext_arr[0]);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])`
+
+error: unnecessary closure used to substitute value for `Option::None`
+  --> $DIR/unnecessary_lazy_eval.rs:46: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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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
+   |
+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 `Result::Err`
+  --> $DIR/unnecessary_lazy_eval.rs:84: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
+   |
+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
+   |
+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
+
diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed
index 813cdaecaa9..8a9b0cd3cf0 100644
--- a/tests/ui/useless_conversion.fixed
+++ b/tests/ui/useless_conversion.fixed
@@ -64,4 +64,9 @@ fn main() {
     let _ = "".lines();
     let _ = vec![1, 2, 3].into_iter();
     let _: String = format!("Hello {}", "world");
+
+    // keep parenthesis around `a + b` for suggestion (see #4750)
+    let a: i32 = 1;
+    let b: i32 = 1;
+    let _ = (a + b) * 3;
 }
diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs
index 540fea23b36..4faa1572973 100644
--- a/tests/ui/useless_conversion.rs
+++ b/tests/ui/useless_conversion.rs
@@ -64,4 +64,9 @@ fn main() {
     let _ = "".lines().into_iter();
     let _ = vec![1, 2, 3].into_iter().into_iter();
     let _: String = format!("Hello {}", "world").into();
+
+    // keep parenthesis around `a + b` for suggestion (see #4750)
+    let a: i32 = 1;
+    let b: i32 = 1;
+    let _ = i32::from(a + b) * 3;
 }
diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr
index b958b035452..f1e880d2696 100644
--- a/tests/ui/useless_conversion.stderr
+++ b/tests/ui/useless_conversion.stderr
@@ -64,5 +64,11 @@ error: useless conversion to the same type
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
-error: aborting due to 10 previous errors
+error: useless conversion to the same type
+  --> $DIR/useless_conversion.rs:71:13
+   |
+LL |     let _ = i32::from(a + b) * 3;
+   |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed
index e73a791891f..85677159620 100644
--- a/tests/ui/vec.fixed
+++ b/tests/ui/vec.fixed
@@ -52,4 +52,11 @@ fn main() {
     for a in vec![NonCopy, NonCopy] {
         println!("{:?}", a);
     }
+
+    on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
+
+    // Ok
+    for a in vec![1; 201] {
+        println!("{:?}", a);
+    }
 }
diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs
index 3eb960f53d7..03b8ee81665 100644
--- a/tests/ui/vec.rs
+++ b/tests/ui/vec.rs
@@ -52,4 +52,11 @@ fn main() {
     for a in vec![NonCopy, NonCopy] {
         println!("{:?}", a);
     }
+
+    on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
+
+    // Ok
+    for a in vec![1; 201] {
+        println!("{:?}", a);
+    }
 }
diff --git a/util/dev b/util/dev
deleted file mode 100755
index 319de217e0d..00000000000
--- a/util/dev
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-CARGO_TARGET_DIR=$(pwd)/target/
-export CARGO_TARGET_DIR
-
-echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
-
-cd clippy_dev && cargo run -- "$@"