about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorflip1995 <hello@philkrones.com>2021-01-30 18:06:34 +0100
committerflip1995 <hello@philkrones.com>2021-01-30 18:06:34 +0100
commit21758bf1fbeb0993fe39daf073b4bf883d36e779 (patch)
tree24e6ce5e1552a540571c7f92c951254e1e0b2119 /src/tools/clippy/clippy_lints
parent7ce1b3b24491cbe10669cbe2b5733c2fe7cfe5b7 (diff)
parent95c0459217d1661edfa794c8bb122452b92fb485 (diff)
downloadrust-21758bf1fbeb0993fe39daf073b4bf883d36e779.tar.gz
rust-21758bf1fbeb0993fe39daf073b4bf883d36e779.zip
Merge commit '95c0459217d1661edfa794c8bb122452b92fb485' into clippyup
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_match.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/main_recursion.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs219
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/diagnostics.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/higher.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/hir_utils.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs137
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
35 files changed, 858 insertions, 207 deletions
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index 0c8efd75514..c30d65bbc57 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -8,6 +8,14 @@ use crate::utils::span_lint_and_help;
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `as` conversions.
     ///
+    /// Note that this lint is specialized in linting *every single* use of `as`
+    /// regardless of whether good alternatives exist or not.
+    /// If you want more precise lints for `as`, please consider using these separate lints:
+    /// `unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`,
+    /// `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
+    /// There is a good explanation the reason why this lint should work in this way and how it is useful
+    /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
+    ///
     /// **Why is this bad?** `as` conversions will perform many kinds of
     /// conversions, including silently lossy conversions and dangerous coercions.
     /// There are cases when it makes sense to use `as`, so the lint is
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index f136aa4572a..ae64c688744 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
     /// other solution is to ensure the mutex is unlocked before calling await,
     /// either by introducing a scope or an explicit call to Drop::drop.
     ///
-    /// **Known problems:** None.
+    /// **Known problems:** Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
     ///
     /// **Example:**
     ///
@@ -57,7 +57,7 @@ declare_clippy_lint! {
     /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
     /// risks panics from a mutable ref shared while other refs are outstanding.
     ///
-    /// **Known problems:** None.
+    /// **Known problems:** Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
     ///
     /// **Example:**
     ///
diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
new file mode 100644
index 00000000000..6969ac949d8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
@@ -0,0 +1,86 @@
+use crate::utils::paths::STRING;
+use crate::utils::{match_def_path, span_lint_and_help};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind, PathSegment};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{source_map::Spanned, Span};
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Checks for calls to `ends_with` with possible file extensions
+    /// and suggests to use a case-insensitive approach instead.
+    ///
+    /// **Why is this bad?**
+    /// `ends_with` is case-sensitive and may not detect files with a valid extension.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// fn is_rust_file(filename: &str) -> bool {
+    ///     filename.ends_with(".rs")
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn is_rust_file(filename: &str) -> bool {
+    ///     filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true)
+    /// }
+    /// ```
+    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    pedantic,
+    "Checks for calls to ends_with with case-sensitive file extensions"
+}
+
+declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]);
+
+fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
+    if_chain! {
+        if let ExprKind::MethodCall(PathSegment { ident, .. }, _, [obj, extension, ..], span) = expr.kind;
+        if ident.as_str() == "ends_with";
+        if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
+        if (2..=6).contains(&ext_literal.as_str().len());
+        if ext_literal.as_str().starts_with('.');
+        if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_digit(10))
+            || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_digit(10));
+        then {
+            let mut ty = ctx.typeck_results().expr_ty(obj);
+            ty = match ty.kind() {
+                ty::Ref(_, ty, ..) => ty,
+                _ => ty
+            };
+
+            match ty.kind() {
+                ty::Str => {
+                    return Some(span);
+                },
+                ty::Adt(&ty::AdtDef { did, .. }, _) => {
+                    if match_def_path(ctx, did, &STRING) {
+                        return Some(span);
+                    }
+                },
+                _ => { return None; }
+            }
+        }
+    }
+    None
+}
+
+impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
+    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
+            span_lint_and_help(
+                ctx,
+                CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+                span,
+                "case-sensitive file extension comparison",
+                None,
+                "consider using a case-insensitive comparison instead",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index b3ebdf4ca30..f21a734bb43 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -57,9 +57,9 @@ impl CognitiveComplexity {
 
         let expr = &body.value;
 
-        let mut helper = CCHelper { cc: 1, returns: 0 };
+        let mut helper = CcHelper { cc: 1, returns: 0 };
         helper.visit_expr(expr);
-        let CCHelper { cc, returns } = helper;
+        let CcHelper { cc, returns } = helper;
         let ret_ty = cx.typeck_results().node_type(expr.hir_id);
         let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) {
             returns
@@ -136,12 +136,12 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
     }
 }
 
-struct CCHelper {
+struct CcHelper {
     cc: u64,
     returns: u64,
 }
 
-impl<'tcx> Visitor<'tcx> for CCHelper {
+impl<'tcx> Visitor<'tcx> for CcHelper {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
index a34ba2d00a8..604ba102046 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
@@ -2,7 +2,7 @@ use crate::utils::visitors::LocalUsedVisitor;
 use crate::utils::{span_lint_and_then, SpanlessEq};
 use if_chain::if_chain;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -72,8 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
         if arms_inner.iter().all(|arm| arm.guard.is_none());
         // match expression must be a local binding
         // match <local> { .. }
-        if let ExprKind::Path(QPath::Resolved(None, path)) = expr_in.kind;
-        if let Res::Local(binding_id) = path.res;
+        if let Some(binding_id) = addr_adjusted_binding(expr_in, cx);
         // one of the branches must be "wild-like"
         if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx));
         let (wild_inner_arm, non_wild_inner_arm) =
@@ -85,7 +84,12 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
         // the "wild-like" branches must be equal
         if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body);
         // the binding must not be used in the if guard
-        if !matches!(arm.guard, Some(Guard::If(guard)) if LocalUsedVisitor::new(binding_id).check_expr(guard));
+        if match arm.guard {
+            None => true,
+            Some(Guard::If(expr) | Guard::IfLet(_, expr)) => {
+                !LocalUsedVisitor::new(binding_id).check_expr(expr)
+            }
+        };
         // ...or anywhere in the inner match
         if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm));
         then {
@@ -170,3 +174,20 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool {
     }
     false
 }
+
+/// Retrieves a binding ID with optional `&` and/or `*` operators removed. (e.g. `&**foo`)
+/// Returns `None` if a non-reference type is de-referenced.
+/// For example, if `Vec` is de-referenced to a slice, `None` is returned.
+fn addr_adjusted_binding(mut expr: &Expr<'_>, cx: &LateContext<'_>) -> Option<HirId> {
+    loop {
+        match expr.kind {
+            ExprKind::AddrOf(_, _, e) => expr = e,
+            ExprKind::Path(QPath::Resolved(None, path)) => match path.res {
+                Res::Local(binding_id) => break Some(binding_id),
+                _ => break None,
+            },
+            ExprKind::Unary(UnOp::UnDeref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
+            _ => break None,
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 47b3cc3ad30..89088c533ed 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -179,3 +179,12 @@ declare_deprecated_lint! {
     pub UNKNOWN_CLIPPY_LINTS,
     "this lint has been integrated into the `unknown_lints` rustc lint"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** This lint has been replaced by `manual_find_map`, a
+    /// more specific lint.
+    pub FIND_MAP,
+    "this lint has been replaced by `manual_find_map`, a more specific lint"
+}
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index ae56a8ba5ab..aa235642ac3 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -5,8 +5,8 @@ use crate::consts::{miri_to_const, Constant};
 use crate::utils::span_lint;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, IntTy, UintTy};
 use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::{self, IntTy, UintTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::convert::TryFrom;
 
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
new file mode 100644
index 00000000000..32b1299efce
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -0,0 +1,102 @@
+use crate::utils::{indent_of, span_lint_and_then};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
+    ///
+    /// **Why is this bad?** Exhaustive enums are typically fine, but a project which does
+    /// not wish to make a stability commitment around exported enums may wish to
+    /// disable them by default.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// enum Foo {
+    ///     Bar,
+    ///     Baz
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[non_exhaustive]
+    /// enum Foo {
+    ///     Bar,
+    ///     Baz
+    /// }
+    /// ```
+    pub EXHAUSTIVE_ENUMS,
+    restriction,
+    "detects exported enums that have not been marked #[non_exhaustive]"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
+    ///
+    /// **Why is this bad?** Exhaustive structs are typically fine, but a project which does
+    /// not wish to make a stability commitment around exported structs may wish to
+    /// disable them by default.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct Foo {
+    ///     bar: u8,
+    ///     baz: String,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[non_exhaustive]
+    /// struct Foo {
+    ///     bar: u8,
+    ///     baz: String,
+    /// }
+    /// ```
+    pub EXHAUSTIVE_STRUCTS,
+    restriction,
+    "detects exported structs that have not been marked #[non_exhaustive]"
+}
+
+declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
+
+impl LateLintPass<'_> for ExhaustiveItems {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if_chain! {
+            if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
+            if cx.access_levels.is_exported(item.hir_id);
+            if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
+            then {
+                let (lint, msg) = if let ItemKind::Enum(..) = item.kind {
+                    (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
+                } else {
+                    (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
+                };
+                let suggestion_span = item.span.shrink_to_lo();
+                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
+                span_lint_and_then(
+                    cx,
+                    lint,
+                    item.span,
+                    msg,
+                    |diag| {
+                        let sugg = format!("#[non_exhaustive]\n{}", indent);
+                        diag.span_suggestion(suggestion_span,
+                                             "try adding #[non_exhaustive]",
+                                             sugg,
+                                             Applicability::MaybeIncorrect);
+                    }
+                );
+
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index a3a38fad9a3..7208e66ff7b 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                         |db| {
                             cx.tcx.infer_ctxt().enter(|infcx| {
                                 for FulfillmentError { obligation, .. } in send_errors {
-                                    infcx.maybe_note_obligation_cause_for_async_await(
-                                        db,
-                                        &obligation,
-                                    );
-                                    if let Trait(trait_pred, _) =
-                                        obligation.predicate.kind().skip_binder()
-                                    {
+                                    infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
+                                    if let Trait(trait_pred, _) = obligation.predicate.kind().skip_binder() {
                                         db.note(&format!(
                                             "`{}` doesn't implement `{}`",
                                             trait_pred.self_ty(),
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index c629ee05ab9..260b8988d37 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -46,8 +46,8 @@ declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]);
 
 #[derive(Copy, Clone)]
 enum Side {
-    LHS,
-    RHS,
+    Lhs,
+    Rhs,
 }
 
 impl IntPlusOne {
@@ -66,11 +66,11 @@ impl IntPlusOne {
                 match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
                     // `-1 + x`
                     (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
-                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
+                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
                     },
                     // `x - 1`
                     (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
+                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
                     },
                     _ => None,
                 }
@@ -82,10 +82,10 @@ impl IntPlusOne {
                 match (&rhslhs.kind, &rhsrhs.kind) {
                     // `y + 1` and `1 + y`
                     (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
+                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
                     },
                     (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
+                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
                     },
                     _ => None,
                 }
@@ -97,10 +97,10 @@ impl IntPlusOne {
                 match (&lhslhs.kind, &lhsrhs.kind) {
                     // `1 + x` and `x + 1`
                     (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
+                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
                     },
                     (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
+                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
                     },
                     _ => None,
                 }
@@ -110,11 +110,11 @@ impl IntPlusOne {
                 match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
                     // `-1 + y`
                     (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
-                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
+                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
                     },
                     // `y - 1`
                     (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
-                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
+                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
                     },
                     _ => None,
                 }
@@ -138,8 +138,8 @@ impl IntPlusOne {
         if let Some(snippet) = snippet_opt(cx, node.span) {
             if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
                 let rec = match side {
-                    Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
-                    Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
+                    Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
+                    Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
                 };
                 return rec;
             }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 781282cdfbd..54007c29c6c 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -170,6 +170,7 @@ mod blocks_in_if_conditions;
 mod booleans;
 mod bytecount;
 mod cargo_common_metadata;
+mod case_sensitive_file_extension_comparisons;
 mod checked_conversions;
 mod cognitive_complexity;
 mod collapsible_if;
@@ -199,6 +200,7 @@ mod escape;
 mod eta_reduction;
 mod eval_order_dependence;
 mod excessive_bools;
+mod exhaustive_items;
 mod exit;
 mod explicit_write;
 mod fallible_impl_from;
@@ -300,6 +302,7 @@ mod redundant_closure_call;
 mod redundant_else;
 mod redundant_field_names;
 mod redundant_pub_crate;
+mod redundant_slicing;
 mod redundant_static_lifetimes;
 mod ref_option_ref;
 mod reference;
@@ -339,6 +342,7 @@ mod unused_self;
 mod unused_unit;
 mod unwrap;
 mod unwrap_in_result;
+mod upper_case_acronyms;
 mod use_self;
 mod useless_conversion;
 mod vec;
@@ -506,6 +510,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "clippy::unknown_clippy_lints",
         "this lint has been integrated into the `unknown_lints` rustc lint",
     );
+    store.register_removed(
+        "clippy::find_map",
+        "this lint has been replaced by `manual_find_map`, a more specific lint",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -561,6 +569,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &booleans::NONMINIMAL_BOOL,
         &bytecount::NAIVE_BYTECOUNT,
         &cargo_common_metadata::CARGO_COMMON_METADATA,
+        &case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
         &checked_conversions::CHECKED_CONVERSIONS,
         &cognitive_complexity::COGNITIVE_COMPLEXITY,
         &collapsible_if::COLLAPSIBLE_ELSE_IF,
@@ -610,6 +619,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &eval_order_dependence::EVAL_ORDER_DEPENDENCE,
         &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
         &excessive_bools::STRUCT_EXCESSIVE_BOOLS,
+        &exhaustive_items::EXHAUSTIVE_ENUMS,
+        &exhaustive_items::EXHAUSTIVE_STRUCTS,
         &exit::EXIT,
         &explicit_write::EXPLICIT_WRITE,
         &fallible_impl_from::FALLIBLE_IMPL_FROM,
@@ -731,11 +742,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::FILTER_MAP,
         &methods::FILTER_MAP_NEXT,
         &methods::FILTER_NEXT,
-        &methods::FIND_MAP,
         &methods::FLAT_MAP_IDENTITY,
         &methods::FROM_ITER_INSTEAD_OF_COLLECT,
         &methods::GET_UNWRAP,
         &methods::INEFFICIENT_TO_STRING,
+        &methods::INSPECT_FOR_EACH,
         &methods::INTO_ITER_ON_REF,
         &methods::ITERATOR_STEP_BY_ZERO,
         &methods::ITER_CLONED_COLLECT,
@@ -743,6 +754,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::ITER_NTH,
         &methods::ITER_NTH_ZERO,
         &methods::ITER_SKIP_NEXT,
+        &methods::MANUAL_FILTER_MAP,
+        &methods::MANUAL_FIND_MAP,
         &methods::MANUAL_SATURATING_ARITHMETIC,
         &methods::MAP_COLLECT_RESULT_UNIT,
         &methods::MAP_FLATTEN,
@@ -850,6 +863,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &redundant_else::REDUNDANT_ELSE,
         &redundant_field_names::REDUNDANT_FIELD_NAMES,
         &redundant_pub_crate::REDUNDANT_PUB_CRATE,
+        &redundant_slicing::REDUNDANT_SLICING,
         &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
         &ref_option_ref::REF_OPTION_REF,
         &reference::DEREF_ADDROF,
@@ -942,6 +956,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &unwrap::PANICKING_UNWRAP,
         &unwrap::UNNECESSARY_UNWRAP,
         &unwrap_in_result::UNWRAP_IN_RESULT,
+        &upper_case_acronyms::UPPER_CASE_ACRONYMS,
         &use_self::USE_SELF,
         &useless_conversion::USELESS_CONVERSION,
         &vec::USELESS_VEC,
@@ -981,7 +996,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     }
     store.register_late_pass(|| box utils::author::Author);
     store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
-    store.register_late_pass(|| box serde_api::SerdeAPI);
+    store.register_late_pass(|| box serde_api::SerdeApi);
     let vec_box_size_threshold = conf.vec_box_size_threshold;
     store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
     store.register_late_pass(|| box booleans::NonminimalBool);
@@ -1092,6 +1107,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
     store.register_late_pass(|| box missing_doc::MissingDoc::new());
     store.register_late_pass(|| box missing_inline::MissingInline);
+    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
     store.register_late_pass(|| box if_let_some_result::OkIfLet);
     store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
     store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
@@ -1172,6 +1188,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
     store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
     store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+    store.register_early_pass(|| box upper_case_acronyms::UpperCaseAcronyms);
     store.register_late_pass(|| box default::Default::default());
     store.register_late_pass(|| box unused_self::UnusedSelf);
     store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
@@ -1229,6 +1246,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
     store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
     store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
+    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1239,6 +1258,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&create_dir::CREATE_DIR),
         LintId::of(&dbg_macro::DBG_MACRO),
         LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+        LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
+        LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
         LintId::of(&exit::EXIT),
         LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
         LintId::of(&implicit_return::IMPLICIT_RETURN),
@@ -1286,6 +1307,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
         LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
         LintId::of(&bit_mask::VERBOSE_BIT_MASK),
+        LintId::of(&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
         LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
         LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
         LintId::of(&copy_iterator::COPY_ITERATOR),
@@ -1323,7 +1345,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&matches::SINGLE_MATCH_ELSE),
         LintId::of(&methods::FILTER_MAP),
         LintId::of(&methods::FILTER_MAP_NEXT),
-        LintId::of(&methods::FIND_MAP),
         LintId::of(&methods::INEFFICIENT_TO_STRING),
         LintId::of(&methods::MAP_FLATTEN),
         LintId::of(&methods::MAP_UNWRAP_OR),
@@ -1509,6 +1530,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::FILTER_NEXT),
         LintId::of(&methods::FLAT_MAP_IDENTITY),
         LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
+        LintId::of(&methods::INSPECT_FOR_EACH),
         LintId::of(&methods::INTO_ITER_ON_REF),
         LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
         LintId::of(&methods::ITER_CLONED_COLLECT),
@@ -1516,6 +1538,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::ITER_NTH),
         LintId::of(&methods::ITER_NTH_ZERO),
         LintId::of(&methods::ITER_SKIP_NEXT),
+        LintId::of(&methods::MANUAL_FILTER_MAP),
+        LintId::of(&methods::MANUAL_FIND_MAP),
         LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
         LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(&methods::NEW_RET_NO_SELF),
@@ -1589,6 +1613,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&redundant_clone::REDUNDANT_CLONE),
         LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
+        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
@@ -1651,6 +1676,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unused_unit::UNUSED_UNIT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
+        LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&vec::USELESS_VEC),
         LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
@@ -1767,6 +1793,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         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(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
         LintId::of(&write::PRINTLN_EMPTY_STRING),
         LintId::of(&write::PRINT_LITERAL),
         LintId::of(&write::PRINT_WITH_NEWLINE),
@@ -1808,6 +1835,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::CLONE_ON_COPY),
         LintId::of(&methods::FILTER_NEXT),
         LintId::of(&methods::FLAT_MAP_IDENTITY),
+        LintId::of(&methods::INSPECT_FOR_EACH),
+        LintId::of(&methods::MANUAL_FILTER_MAP),
+        LintId::of(&methods::MANUAL_FIND_MAP),
         LintId::of(&methods::OPTION_AS_REF_DEREF),
         LintId::of(&methods::SEARCH_IS_SOME),
         LintId::of(&methods::SKIP_WHILE_NEXT),
@@ -1832,6 +1862,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
         LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
         LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
+        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
         LintId::of(&repeat_once::REPEAT_ONCE),
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index f89075005bc..5211ca7da32 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -1069,7 +1069,6 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>(
 ) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> + 'c {
     // As the `filter` and `map` below do different things, I think putting together
     // just increases complexity. (cc #3188 and #4193)
-    #[allow(clippy::filter_map)]
     stmts
         .iter()
         .filter_map(move |stmt| match stmt.kind {
diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs
index eceae706e4f..1ed3f3de839 100644
--- a/src/tools/clippy/clippy_lints/src/main_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs
@@ -43,8 +43,7 @@ impl LateLintPass<'_> for MainRecursion {
 
         if_chain! {
             if let ExprKind::Call(func, _) = &expr.kind;
-            if let ExprKind::Path(path) = &func.kind;
-            if let QPath::Resolved(_, path) = &path;
+            if let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind;
             if let Some(def_id) = path.res.opt_def_id();
             if is_entrypoint_fn(cx, def_id);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
index b97d97ea1a5..8c77e155b70 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
@@ -23,9 +23,6 @@ declare_clippy_lint! {
     /// ```rust
     /// let foo: Option<i32> = None;
     /// foo.map_or(Err("error"), |v| Ok(v));
-    ///
-    /// let foo: Option<i32> = None;
-    /// foo.map_or(Err("error"), |v| Ok(v));
     /// ```
     ///
     /// Use instead:
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index e50d11a4d71..01126e86199 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -131,7 +131,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) ->
             Some(expr.span)
         },
         hir::ExprKind::Block(ref block, _) => {
-            match (&block.stmts[..], block.expr.as_ref()) {
+            match (block.stmts, block.expr.as_ref()) {
                 (&[], Some(inner_expr)) => {
                     // If block only contains an expression,
                     // reduce `{ X }` to `X`
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 04b35835c6b..5f62d2d1316 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -2,10 +2,10 @@ use crate::consts::{constant, miri_to_const, Constant};
 use crate::utils::sugg::Sugg;
 use crate::utils::usage::is_unused;
 use crate::utils::{
-    expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
-    is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks,
-    snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note,
-    span_lint_and_sugg, span_lint_and_then,
+    expr_block, get_arg_name, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of,
+    is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg,
+    peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt,
+    snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
 use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
 use if_chain::if_chain;
@@ -728,20 +728,60 @@ fn report_single_match_single_pattern(
     let els_str = els.map_or(String::new(), |els| {
         format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
     });
+
+    let (msg, sugg) = if_chain! {
+        let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
+        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
+        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
+        if let Some(trait_id) = cx.tcx.lang_items().structural_peq_trait();
+        if ty.is_integral() || ty.is_char() || ty.is_str() || implements_trait(cx, ty, trait_id, &[]);
+        then {
+            // scrutinee derives PartialEq and the pattern is a constant.
+            let pat_ref_count = match pat.kind {
+                // string literals are already a reference.
+                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
+                _ => pat_ref_count,
+            };
+            // References are only implicitly added to the pattern, so no overflow here.
+            // e.g. will work: match &Some(_) { Some(_) => () }
+            // will not: match Some(_) { &Some(_) => () }
+            let ref_count_diff = ty_ref_count - pat_ref_count;
+
+            // Try to remove address of expressions first.
+            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
+            let ref_count_diff = ref_count_diff - removed;
+
+            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
+            let sugg = format!(
+                "if {} == {}{} {}{}",
+                snippet(cx, ex.span, ".."),
+                // PartialEq for different reference counts may not exist.
+                "&".repeat(ref_count_diff),
+                snippet(cx, arms[0].pat.span, ".."),
+                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
+                els_str,
+            );
+            (msg, sugg)
+        } else {
+            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
+            let sugg = format!(
+                "if let {} = {} {}{}",
+                snippet(cx, arms[0].pat.span, ".."),
+                snippet(cx, ex.span, ".."),
+                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
+                els_str,
+            );
+            (msg, sugg)
+        }
+    };
+
     span_lint_and_sugg(
         cx,
         lint,
         expr.span,
-        "you seem to be trying to use match for destructuring a single pattern. Consider using `if \
-         let`",
+        msg,
         "try this",
-        format!(
-            "if let {} = {} {}{}",
-            snippet(cx, arms[0].pat.span, ".."),
-            snippet(cx, ex.span, ".."),
-            expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
-            els_str,
-        ),
+        sugg,
         Applicability::HasPlaceholders,
     );
 }
@@ -1185,6 +1225,14 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
             } else {
                 pat
             };
+
+            // strip potential borrows (#6503), but only if the type is a reference
+            let mut ex_new = ex;
+            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
+                if let ty::Ref(..) = cx.typeck_results().expr_ty(&ex_inner).kind() {
+                    ex_new = ex_inner;
+                }
+            };
             span_lint_and_sugg(
                 cx,
                 MATCH_LIKE_MATCHES_MACRO,
@@ -1194,7 +1242,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
                 format!(
                     "{}matches!({}, {})",
                     if b0 { "" } else { "!" },
-                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
                     pat_and_guard,
                 ),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
new file mode 100644
index 00000000000..6d41ee38a27
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
@@ -0,0 +1,23 @@
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::source_map::Span;
+
+use crate::utils::{match_trait_method, paths, span_lint_and_help};
+
+use super::INSPECT_FOR_EACH;
+
+/// lint use of `inspect().for_each()` for `Iterators`
+pub(super) fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) {
+    if match_trait_method(cx, expr, &paths::ITERATOR) {
+        let msg = "called `inspect(..).for_each(..)` on an `Iterator`";
+        let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`";
+        span_lint_and_help(
+            cx,
+            INSPECT_FOR_EACH,
+            inspect_span.with_hi(expr.span.hi()),
+            msg,
+            None,
+            hint,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 7adf6bdeac5..a17c5996293 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1,5 +1,6 @@
 mod bind_instead_of_map;
 mod inefficient_to_string;
+mod inspect_for_each;
 mod manual_saturating_arithmetic;
 mod option_map_unwrap_or;
 mod unnecessary_filter_map;
@@ -14,7 +15,8 @@ use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::{TraitItem, TraitItemKind};
+use rustc_hir::def::Res;
+use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
@@ -450,6 +452,58 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply
+    /// as `filter_map(_)`.
+    ///
+    /// **Why is this bad?** Redundant code in the `filter` and `map` operations is poor style and
+    /// less performant.
+    ///
+    /// **Known problems:** None.
+    ///
+     /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// (0_i32..10)
+    ///     .filter(|n| n.checked_add(1).is_some())
+    ///     .map(|n| n.checked_add(1).unwrap());
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// (0_i32..10).filter_map(|n| n.checked_add(1));
+    /// ```
+    pub MANUAL_FILTER_MAP,
+    complexity,
+    "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.find(_).map(_)` that can be written more simply
+    /// as `find_map(_)`.
+    ///
+    /// **Why is this bad?** Redundant code in the `find` and `map` operations is poor style and
+    /// less performant.
+    ///
+    /// **Known problems:** None.
+    ///
+     /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// (0_i32..10)
+    ///     .find(|n| n.checked_add(1).is_some())
+    ///     .map(|n| n.checked_add(1).unwrap());
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// (0_i32..10).find_map(|n| n.checked_add(1));
+    /// ```
+    pub MANUAL_FIND_MAP,
+    complexity,
+    "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
+}
+
+declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
     ///
     /// **Why is this bad?** Readability, this can be written more concisely as
@@ -494,28 +548,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `_.find(_).map(_)`.
-    ///
-    /// **Why is this bad?** Readability, this can be written more concisely as
-    /// `_.find_map(_)`.
-    ///
-    /// **Known problems:** Often requires a condition + Option/Iterator creation
-    /// inside the closure.
-    ///
-    /// **Example:**
-    /// ```rust
-    ///  (0..3).find(|x| *x == 2).map(|x| x * 2);
-    /// ```
-    /// Can be written as
-    /// ```rust
-    ///  (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
-    /// ```
-    pub FIND_MAP,
-    pedantic,
-    "using a combination of `find` and `map` can usually be written as a single method call"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Checks for an iterator or string search (such as `find()`,
     /// `position()`, or `rposition()`) followed by a call to `is_some()`.
     ///
@@ -1405,6 +1437,36 @@ declare_clippy_lint! {
     "use `.collect()` instead of `::from_iter()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `inspect().for_each()`.
+    ///
+    /// **Why is this bad?** It is the same as performing the computation
+    /// inside `inspect` at the beginning of the closure in `for_each`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// [1,2,3,4,5].iter()
+    /// .inspect(|&x| println!("inspect the number: {}", x))
+    /// .for_each(|&x| {
+    ///     assert!(x >= 0);
+    /// });
+    /// ```
+    /// Can be written as
+    /// ```rust
+    /// [1,2,3,4,5].iter()
+    /// .for_each(|&x| {
+    ///     println!("inspect the number: {}", x);
+    ///     assert!(x >= 0);
+    /// });
+    /// ```
+    pub INSPECT_FOR_EACH,
+    complexity,
+    "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
+}
+
 pub struct Methods {
     msrv: Option<RustcVersion>,
 }
@@ -1442,9 +1504,10 @@ impl_lint_pass!(Methods => [
     FILTER_NEXT,
     SKIP_WHILE_NEXT,
     FILTER_MAP,
+    MANUAL_FILTER_MAP,
+    MANUAL_FIND_MAP,
     FILTER_MAP_NEXT,
     FLAT_MAP_IDENTITY,
-    FIND_MAP,
     MAP_FLATTEN,
     ITERATOR_STEP_BY_ZERO,
     ITER_NEXT_SLICE,
@@ -1467,6 +1530,7 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_LAZY_EVALUATIONS,
     MAP_COLLECT_RESULT_UNIT,
     FROM_ITER_INSTEAD_OF_COLLECT,
+    INSPECT_FOR_EACH,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -1508,10 +1572,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
             ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
             ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
-            ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
+            ["map", "filter"] => lint_filter_map(cx, expr, false),
             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()),
-            ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
+            ["map", "find"] => lint_filter_map(cx, expr, true),
             ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
@@ -1553,6 +1617,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
             ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
             ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]),
+            ["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]),
             _ => {},
         }
 
@@ -2955,18 +3020,79 @@ fn lint_skip_while_next<'tcx>(
     }
 }
 
-/// lint use of `filter().map()` for `Iterators`
-fn lint_filter_map<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    _filter_args: &'tcx [hir::Expr<'_>],
-    _map_args: &'tcx [hir::Expr<'_>],
-) {
-    // lint if caller of `.filter().map()` is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter(..).map(..)` on an `Iterator`";
-        let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
-        span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
+/// lint use of `filter().map()` or `find().map()` for `Iterators`
+fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) {
+    if_chain! {
+        if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
+        if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind;
+        if match_trait_method(cx, map_recv, &paths::ITERATOR);
+
+        // filter(|x| ...is_some())...
+        if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind;
+        let filter_body = cx.tcx.hir().body(filter_body_id);
+        if let [filter_param] = filter_body.params;
+        // optional ref pattern: `filter(|&x| ..)`
+        let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
+            (ref_pat, true)
+        } else {
+            (filter_param.pat, false)
+        };
+        // closure ends with is_some() or is_ok()
+        if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
+        if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
+        if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
+        if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
+            Some(false)
+        } else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
+            Some(true)
+        } else {
+            None
+        };
+        if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+
+        // ...map(|x| ...unwrap())
+        if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind;
+        let map_body = cx.tcx.hir().body(map_body_id);
+        if let [map_param] = map_body.params;
+        if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
+        // closure ends with expect() or unwrap()
+        if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
+        if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
+
+        let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+            // in `filter(|x| ..)`, replace `*x` with `x`
+            let a_path = if_chain! {
+                if !is_filter_param_ref;
+                if let ExprKind::Unary(UnOp::UnDeref, expr_path) = a.kind;
+                then { expr_path } else { a }
+            };
+            // let the filter closure arg and the map closure arg be equal
+            if_chain! {
+                if let ExprKind::Path(QPath::Resolved(None, a_path)) = a_path.kind;
+                if let ExprKind::Path(QPath::Resolved(None, b_path)) = b.kind;
+                if a_path.res == Res::Local(filter_param_id);
+                if b_path.res == Res::Local(map_param_id);
+                if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
+                then {
+                    return true;
+                }
+            }
+            false
+        };
+        if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
+        then {
+            let span = filter_span.to(map_span);
+            let (filter_name, lint) = if is_find {
+                ("find", MANUAL_FIND_MAP)
+            } else {
+                ("filter", MANUAL_FILTER_MAP)
+            };
+            let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
+            let to_opt = if is_result { ".ok()" } else { "" };
+            let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
+                snippet(cx, map_arg.span, ".."), to_opt);
+            span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
+        }
     }
 }
 
@@ -3004,21 +3130,6 @@ fn lint_filter_map_next<'tcx>(
     }
 }
 
-/// lint use of `find().map()` for `Iterators`
-fn lint_find_map<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    _find_args: &'tcx [hir::Expr<'_>],
-    map_args: &'tcx [hir::Expr<'_>],
-) {
-    // lint if caller of `.filter().map()` is an Iterator
-    if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
-        let msg = "called `find(..).map(..)` on an `Iterator`";
-        let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
-        span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
-    }
-}
-
 /// lint use of `filter_map().map()` for `Iterators`
 fn lint_filter_map_map<'tcx>(
     cx: &LateContext<'tcx>,
@@ -3026,7 +3137,7 @@ fn lint_filter_map_map<'tcx>(
     _filter_args: &'tcx [hir::Expr<'_>],
     _map_args: &'tcx [hir::Expr<'_>],
 ) {
-    // lint if caller of `.filter().map()` is an Iterator
+    // lint if caller of `.filter_map().map()` is an Iterator
     if match_trait_method(cx, expr, &paths::ITERATOR) {
         let msg = "called `filter_map(..).map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 89fe2c19a57..54033f40871 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -117,9 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             .filter_map(|obligation| {
                 // Note that we do not want to deal with qualified predicates here.
                 match obligation.predicate.kind().no_bound_vars() {
-                    Some(ty::PredicateKind::Trait(pred, _)) if pred.def_id() != sized_trait => {
-                        Some(pred)
-                    },
+                    Some(ty::PredicateKind::Trait(pred, _)) if pred.def_id() != sized_trait => Some(pred),
                     _ => None,
                 }
             })
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 446426b3e61..855529378e6 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -199,6 +199,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
             );
             return;
         }
+        if interned_name.starts_with('_') {
+            // these bindings are typically unused or represent an ignored portion of a destructuring pattern
+            return;
+        }
         let count = interned_name.chars().count();
         if count < 3 {
             if count == 1 {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index c6329a1381c..b5aa3411140 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -263,8 +263,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
             } else if match_type(cx, ty, &paths::COW) {
                 if_chain! {
                     if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
-                    if let TyKind::Path(ref path) = ty.kind;
-                    if let QPath::Resolved(None, ref pp) = *path;
+                    if let TyKind::Path(QPath::Resolved(None, ref pp)) = ty.kind;
                     if let [ref bx] = *pp.segments;
                     if let Some(ref params) = bx.args;
                     if !params.parenthesized;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
new file mode 100644
index 00000000000..e5ced13514f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -0,0 +1,67 @@
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::{lint::in_external_macro, ty::TyS};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for redundant slicing expressions which use the full range, and
+    /// do not change the type.
+    ///
+    /// **Why is this bad?** It unnecessarily adds complexity to the expression.
+    ///
+    /// **Known problems:** If the type being sliced has an implementation of `Index<RangeFull>`
+    /// that actually changes anything then it can't be removed. However, this would be surprising
+    /// to people reading the code and should have a note with it.
+    ///
+    /// **Example:**
+    ///
+    /// ```ignore
+    /// fn get_slice(x: &[u32]) -> &[u32] {
+    ///     &x[..]
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// fn get_slice(x: &[u32]) -> &[u32] {
+    ///     x
+    /// }
+    /// ```
+    pub REDUNDANT_SLICING,
+    complexity,
+    "redundant slicing of the whole range of a type"
+}
+
+declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
+
+impl LateLintPass<'_> for RedundantSlicing {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::AddrOf(_, _, addressee) = expr.kind;
+            if let ExprKind::Index(indexed, range) = addressee.kind;
+            if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
+            if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
+            then {
+                let mut app = Applicability::MachineApplicable;
+                let hint = snippet_with_applicability(cx, indexed.span, "..", &mut app).into_owned();
+
+                span_lint_and_sugg(
+                    cx,
+                    REDUNDANT_SLICING,
+                    expr.span,
+                    "redundant slicing of the whole range",
+                    "use the original slice instead",
+                    hint,
+                    app,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index efe3237990d..e1450466a7c 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -1,3 +1,4 @@
+use crate::utils::sugg::Sugg;
 use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
@@ -110,6 +111,12 @@ declare_clippy_lint! {
     /// let point = Point(30, 20);
     /// let x = (&point).0;
     /// ```
+    /// Use instead:
+    /// ```rust
+    /// # struct Point(u32, u32);
+    /// # let point = Point(30, 20);
+    /// let x = point.0;
+    /// ```
     pub REF_IN_DEREF,
     complexity,
     "Use of reference in auto dereference expression."
@@ -124,14 +131,19 @@ impl EarlyLintPass for RefInDeref {
             if let ExprKind::Paren(ref parened) = object.kind;
             if let ExprKind::AddrOf(_, _, ref inner) = parened.kind;
             then {
-                let mut applicability = Applicability::MachineApplicable;
+                let applicability = if inner.span.from_expansion() {
+                    Applicability::MaybeIncorrect
+                } else {
+                    Applicability::MachineApplicable
+                };
+                let sugg = Sugg::ast(cx, inner, "_").maybe_par();
                 span_lint_and_sugg(
                     cx,
                     REF_IN_DEREF,
                     object.span,
                     "creating a reference that is immediately dereferenced",
                     "try this",
-                    snippet_with_applicability(cx, inner.span, "_", &mut applicability).to_string(),
+                    sugg.to_string(),
                     applicability,
                 );
             }
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 63548d8fdb4..e438f92b136 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -131,7 +131,16 @@ impl<'tcx> LateLintPass<'tcx> for Return {
         _: HirId,
     ) {
         match kind {
-            FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty),
+            FnKind::Closure(_) => {
+                // when returning without value in closure, replace this `return`
+                // with an empty block to prevent invalid suggestion (see #6501)
+                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
+                    RetReplacement::Block
+                } else {
+                    RetReplacement::Empty
+                };
+                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+            },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(ref block, _) = body.value.kind {
                     check_block_return(cx, block);
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 44e739725c8..90cf1b6c861 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -18,9 +18,9 @@ declare_clippy_lint! {
     "various things that will negatively affect your serde experience"
 }
 
-declare_lint_pass!(SerdeAPI => [SERDE_API_MISUSE]);
+declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]);
 
-impl<'tcx> LateLintPass<'tcx> for SerdeAPI {
+impl<'tcx> LateLintPass<'tcx> for SerdeApi {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
             of_trait: Some(ref trait_ref),
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index ea7a76146f5..87e386baadc 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -35,10 +35,11 @@ declare_clippy_lint! {
 
 declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
 
-fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Ty<'tcx>> {
+fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
     match expr.kind {
         ExprKind::Call(count_func, _func_args) => {
             if_chain! {
+                if !inverted;
                 if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
                 if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
                 if match_def_path(cx, def_id, &paths::MEM_SIZE_OF)
@@ -50,10 +51,13 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Ty<'tc
                 }
             }
         },
-        ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => {
-            get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right))
+        ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node => {
+            get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, inverted))
         },
-        ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr),
+        ExprKind::Binary(op, left, right) if BinOpKind::Div == op.node => {
+            get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, !inverted))
+        },
+        ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr, inverted),
         _ => None,
     }
 }
@@ -128,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
 
             // Find a size_of call in the count parameter expression and
             // check that it's the same type
-            if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr);
+            if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false);
             if TyS::same_type(pointee_ty, ty_used_for_size_of);
             then {
                 span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
index 99e4b293ac6..276a9338819 100644
--- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_slice_of_primitives, span_lint_and_sugg, sugg::Sugg};
+use crate::utils::{is_slice_of_primitives, span_lint_and_then, sugg::Sugg};
 
 use if_chain::if_chain;
 
@@ -107,25 +107,32 @@ fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option
 impl LateLintPass<'_> for StableSortPrimitive {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 STABLE_SORT_PRIMITIVE,
                 expr.span,
                 format!(
-                    "used {} instead of {} to sort primitive type `{}`",
+                    "used `{}` on primitive type `{}`",
                     detection.method.stable_name(),
-                    detection.method.unstable_name(),
                     detection.slice_type,
                 )
                 .as_str(),
-                "try",
-                format!(
-                    "{}.{}({})",
-                    detection.slice_name,
-                    detection.method.unstable_name(),
-                    detection.method_args
-                ),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!(
+                            "{}.{}({})",
+                            detection.slice_name,
+                            detection.method.unstable_name(),
+                            detection.method_args,
+                        ),
+                        Applicability::MachineApplicable,
+                    );
+                    diag.note(
+                        "an unstable sort would perform faster without any observable difference for this data type",
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
new file mode 100644
index 00000000000..61e7031716a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -0,0 +1,93 @@
+use crate::utils::span_lint_and_sugg;
+use if_chain::if_chain;
+use itertools::Itertools;
+use rustc_ast::ast::{Item, ItemKind, Variant};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for camel case name containing a capitalized acronym.
+    ///
+    /// **Why is this bad?** In CamelCase, acronyms count as one word.
+    /// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
+    /// for more.
+    ///
+    /// **Known problems:** When two acronyms are contiguous, the lint can't tell where
+    /// the first acronym ends and the second starts, so it suggests to lowercase all of
+    /// the letters in the second acronym.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct HTTPResponse;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct HttpResponse;
+    /// ```
+    pub UPPER_CASE_ACRONYMS,
+    style,
+    "capitalized acronyms are against the naming convention"
+}
+
+declare_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);
+
+fn correct_ident(ident: &str) -> String {
+    let ident = ident.chars().rev().collect::<String>();
+    let fragments = ident
+        .split_inclusive(|x: char| !x.is_ascii_lowercase())
+        .rev()
+        .map(|x| x.chars().rev().collect::<String>());
+
+    let mut ident = fragments.clone().next().unwrap();
+    for (ref prev, ref curr) in fragments.tuple_windows() {
+        if [prev, curr]
+            .iter()
+            .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
+        {
+            ident.push_str(&curr.to_ascii_lowercase());
+        } else {
+            ident.push_str(curr);
+        }
+    }
+    ident
+}
+
+fn check_ident(cx: &EarlyContext<'_>, ident: &Ident) {
+    let span = ident.span;
+    let ident = &ident.as_str();
+    let corrected = correct_ident(ident);
+    if ident != &corrected {
+        span_lint_and_sugg(
+            cx,
+            UPPER_CASE_ACRONYMS,
+            span,
+            &format!("name `{}` contains a capitalized acronym", ident),
+            "consider making the acronym lowercase, except the initial letter",
+            corrected,
+            Applicability::MaybeIncorrect,
+        )
+    }
+}
+
+impl EarlyLintPass for UpperCaseAcronyms {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+        if_chain! {
+            if !in_external_macro(cx.sess(), it.span);
+            if matches!(
+                it.kind,
+                ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
+            );
+            then {
+                check_ident(cx, &it.ident);
+            }
+        }
+    }
+
+    fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &Variant) {
+        check_ident(cx, &v.ident);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 32d7840a451..b5a8300376c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -127,6 +127,7 @@ define_Conf! {
         "OAuth", "GraphQL",
         "OCaml",
         "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
+        "WebGL",
         "TensorFlow",
         "TrueType",
         "iOS", "macOS",
diff --git a/src/tools/clippy/clippy_lints/src/utils/diagnostics.rs b/src/tools/clippy/clippy_lints/src/utils/diagnostics.rs
index a7a6b5855b7..6caa04f651f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/diagnostics.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/diagnostics.rs
@@ -186,8 +186,6 @@ pub fn span_lint_hir_and_then(
 ///     |
 ///     = note: `-D fold-any` implied by `-D warnings`
 /// ```
-
-#[allow(clippy::unknown_clippy_lints)]
 #[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
 pub fn span_lint_and_sugg<'a, T: LintContext>(
     cx: &'a T,
diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs
index 42ab9a1e7d2..340d340d6d3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/higher.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs
@@ -158,8 +158,7 @@ pub fn for_loop<'tcx>(
 /// `while cond { body }` becomes `(cond, body)`.
 pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
     if_chain! {
-        if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind;
-        if let hir::Block { expr: Some(expr), .. } = &**block;
+        if let hir::ExprKind::Loop(hir::Block { expr: Some(expr), .. }, _, hir::LoopSource::While, _) = &expr.kind;
         if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
         if let hir::ExprKind::DropTemps(cond) = &cond.kind;
         if let [hir::Arm { body, .. }, ..] = &arms[..];
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 6066383f2ef..c5870dc5124 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -24,6 +24,7 @@ pub struct SpanlessEq<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
     allow_side_effects: bool,
+    expr_fallback: Option<Box<dyn Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
 }
 
 impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
@@ -32,6 +33,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
             allow_side_effects: true,
+            expr_fallback: None,
         }
     }
 
@@ -43,6 +45,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
         }
     }
 
+    pub fn expr_fallback(self, expr_fallback: impl Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
+        Self {
+            expr_fallback: Some(Box::new(expr_fallback)),
+            ..self
+        }
+    }
+
     /// Checks whether two statements are the same.
     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
@@ -81,7 +90,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             }
         }
 
-        match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) {
+        let is_eq = match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) {
             (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
             },
@@ -158,7 +167,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
             (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
             _ => false,
-        }
+        };
+        is_eq || self.expr_fallback.as_ref().map_or(false, |f| f(left, right))
     }
 
     fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 0bbb6a52a20..d0db3a67533 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -31,7 +31,6 @@ pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
-use std::mem;
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, Attribute, LitKind};
@@ -39,7 +38,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::Node;
 use rustc_hir::{
@@ -48,6 +47,7 @@ use rustc_hir::{
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
+use rustc_middle::hir::exports::Export;
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
@@ -308,65 +308,43 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
 }
 
 /// Gets the definition associated to a path.
-pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
-    let crates = cx.tcx.crates();
-    let krate = crates
-        .iter()
-        .find(|&&krate| cx.tcx.crate_name(krate).as_str() == path[0]);
-    if let Some(krate) = krate {
-        let krate = DefId {
-            krate: *krate,
-            index: CRATE_DEF_INDEX,
-        };
-        let mut current_item = None;
-        let mut items = cx.tcx.item_children(krate);
-        let mut path_it = path.iter().skip(1).peekable();
-
-        loop {
-            let segment = match path_it.next() {
-                Some(segment) => segment,
-                None => return None,
-            };
-
-            // `get_def_path` seems to generate these empty segments for extern blocks.
-            // We can just ignore them.
-            if segment.is_empty() {
-                continue;
-            }
-
-            let result = SmallVec::<[_; 8]>::new();
-            for item in mem::replace(&mut items, cx.tcx.arena.alloc_slice(&result)).iter() {
-                if item.ident.name.as_str() == *segment {
-                    if path_it.peek().is_none() {
-                        return Some(item.res);
-                    }
-
-                    current_item = Some(item);
-                    items = cx.tcx.item_children(item.res.def_id());
-                    break;
-                }
-            }
+#[allow(clippy::shadow_unrelated)] // false positive #6563
+pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
+    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
+        tcx.item_children(def_id)
+            .iter()
+            .find(|item| item.ident.name.as_str() == name)
+    }
 
-            // The segment isn't a child_item.
-            // Try to find it under an inherent impl.
-            if_chain! {
-                if path_it.peek().is_none();
-                if let Some(current_item) = current_item;
-                let item_def_id = current_item.res.def_id();
-                if cx.tcx.def_kind(item_def_id) == DefKind::Struct;
-                then {
-                    // Bad `find_map` suggestion. See #4193.
-                    #[allow(clippy::find_map)]
-                    return cx.tcx.inherent_impls(item_def_id).iter()
-                        .flat_map(|&impl_def_id| cx.tcx.item_children(impl_def_id))
-                        .find(|item| item.ident.name.as_str() == *segment)
-                        .map(|item| item.res);
-                }
+    let (krate, first, path) = match *path {
+        [krate, first, ref path @ ..] => (krate, first, path),
+        _ => return None,
+    };
+    let tcx = cx.tcx;
+    let crates = tcx.crates();
+    let krate = crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)?;
+    let first = item_child_by_name(tcx, krate.as_def_id(), first)?;
+    let last = path
+        .iter()
+        .copied()
+        // `get_def_path` seems to generate these empty segments for extern blocks.
+        // We can just ignore them.
+        .filter(|segment| !segment.is_empty())
+        // for each segment, find the child item
+        .try_fold(first, |item, segment| {
+            let def_id = item.res.def_id();
+            if let Some(item) = item_child_by_name(tcx, def_id, segment) {
+                Some(item)
+            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
+                // it is not a child item so check inherent impl items
+                tcx.inherent_impls(def_id)
+                    .iter()
+                    .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
+            } else {
+                None
             }
-        }
-    } else {
-        None
-    }
+        })?;
+    Some(last.res)
 }
 
 /// Convenience function to get the `DefId` of a trait by path.
@@ -1134,8 +1112,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if_chain! {
-        if let TyKind::Path(ref qp) = slf.kind;
-        if let QPath::Resolved(None, ref path) = *qp;
+        if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
         if let Res::SelfTy(..) = path.res;
         then {
             return true
@@ -1655,6 +1632,44 @@ where
     match_expr_list
 }
 
+/// Peels off all references on the pattern. Returns the underlying pattern and the number of
+/// references removed.
+pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
+    fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
+        if let PatKind::Ref(pat, _) = pat.kind {
+            peel(pat, count + 1)
+        } else {
+            (pat, count)
+        }
+    }
+    peel(pat, 0)
+}
+
+/// Peels off up to the given number of references on the expression. Returns the underlying
+/// expression and the number of references removed.
+pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
+    fn f(expr: &'a Expr<'a>, count: usize, target: usize) -> (&'a Expr<'a>, usize) {
+        match expr.kind {
+            ExprKind::AddrOf(_, _, expr) if count != target => f(expr, count + 1, target),
+            _ => (expr, count),
+        }
+    }
+    f(expr, 0, count)
+}
+
+/// Peels off all references on the type. Returns the underlying type and the number of references
+/// removed.
+pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
+    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
+        if let ty::Ref(_, ty, _) = ty.kind() {
+            peel(ty, count + 1)
+        } else {
+            (ty, count)
+        }
+    }
+    peel(ty, 0)
+}
+
 #[macro_export]
 macro_rules! unwrap_cargo_metadata {
     ($cx: ident, $lint: ident, $deps: expr) => {{
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index af324f831df..6358104eeda 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -2,7 +2,8 @@ use std::borrow::Cow;
 use std::ops::Range;
 
 use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
-use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, MacCall, StrLit, StrStyle};
+use if_chain::if_chain;
+use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle};
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::Applicability;
@@ -437,7 +438,7 @@ impl Write {
                 return (Some(fmtstr), None);
             };
             match &token_expr.kind {
-                ExprKind::Lit(_) => {
+                ExprKind::Lit(lit) if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) => {
                     let mut all_simple = true;
                     let mut seen = false;
                     for arg in &args {
@@ -457,8 +458,11 @@ impl Write {
                     idx += 1;
                 },
                 ExprKind::Assign(lhs, rhs, _) => {
-                    if let ExprKind::Lit(_) = rhs.kind {
-                        if let ExprKind::Path(_, p) = &lhs.kind {
+                    if_chain! {
+                        if let ExprKind::Lit(ref lit) = rhs.kind;
+                        if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..));
+                        if let ExprKind::Path(_, p) = &lhs.kind;
+                        then {
                             let mut all_simple = true;
                             let mut seen = false;
                             for arg in &args {
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 9761e822a7a..319b85ac42a 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -6,7 +6,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_target::abi::LayoutOf as _;
 use rustc_typeck::hir_ty_to_ty;
 
-use crate::utils::{is_type_diagnostic_item, match_type, paths, span_lint_and_help};
+use crate::utils::{is_normalizable, is_type_diagnostic_item, match_type, paths, span_lint_and_help};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for maps with zero-sized value types anywhere in the code.
@@ -50,6 +50,8 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP);
             if let Adt(_, ref substs) = ty.kind();
             let ty = substs.type_at(1);
+            // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`.
+            if is_normalizable(cx, cx.param_env, ty);
             if let Ok(layout) = cx.layout_of(ty);
             if layout.is_zst();
             then {