about summary refs log tree commit diff
path: root/clippy_lints
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2022-09-09 13:36:26 +0200
committerPhilipp Krones <hello@philkrones.com>2022-09-09 13:36:26 +0200
commit98bf99e2f8cf8b357d63a67ce67d5fc5ceef8b3c (patch)
tree9737ff22b257f29282e7538d9ecb264451a3c1c0 /clippy_lints
parent854f751b263dfac06dc3f635f8a9f92b8bc51da6 (diff)
downloadrust-98bf99e2f8cf8b357d63a67ce67d5fc5ceef8b3c.tar.gz
rust-98bf99e2f8cf8b357d63a67ce67d5fc5ceef8b3c.zip
Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup
Diffstat (limited to 'clippy_lints')
-rw-r--r--clippy_lints/src/async_yields_async.rs2
-rw-r--r--clippy_lints/src/attrs.rs6
-rw-r--r--clippy_lints/src/bool_to_int_with_if.rs125
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs21
-rw-r--r--clippy_lints/src/dereference.rs31
-rw-r--r--clippy_lints/src/derivable_impls.rs2
-rw-r--r--clippy_lints/src/doc.rs8
-rw-r--r--clippy_lints/src/eta_reduction.rs9
-rw-r--r--clippy_lints/src/fallible_impl_from.rs4
-rw-r--r--clippy_lints/src/floating_point_arithmetic.rs30
-rw-r--r--clippy_lints/src/functions/must_use.rs2
-rw-r--r--clippy_lints/src/functions/result.rs10
-rw-r--r--clippy_lints/src/implicit_return.rs4
-rw-r--r--clippy_lints/src/infinite_iter.rs10
-rw-r--r--clippy_lints/src/large_enum_variant.rs96
-rw-r--r--clippy_lints/src/len_zero.rs16
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_lints.rs3
-rw-r--r--clippy_lints/src/lib.register_restriction.rs2
-rw-r--r--clippy_lints/src/lib.register_style.rs1
-rw-r--r--clippy_lints/src/lib.rs12
-rw-r--r--clippy_lints/src/lifetimes.rs2
-rw-r--r--clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--clippy_lints/src/loops/while_let_on_iterator.rs2
-rw-r--r--clippy_lints/src/matches/match_wild_err_arm.rs2
-rw-r--r--clippy_lints/src/matches/single_match.rs8
-rw-r--r--clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--clippy_lints/src/methods/chars_cmp.rs2
-rw-r--r--clippy_lints/src/methods/clone_on_copy.rs6
-rw-r--r--clippy_lints/src/methods/filter_map.rs2
-rw-r--r--clippy_lints/src/methods/map_clone.rs2
-rw-r--r--clippy_lints/src/methods/mod.rs5
-rw-r--r--clippy_lints/src/methods/mut_mutex_lock.rs3
-rw-r--r--clippy_lints/src/methods/open_options.rs2
-rw-r--r--clippy_lints/src/methods/option_as_ref_deref.rs2
-rw-r--r--clippy_lints/src/methods/option_map_or_none.rs2
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs13
-rw-r--r--clippy_lints/src/methods/suspicious_map.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_filter_map.rs11
-rw-r--r--clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--clippy_lints/src/methods/unnecessary_sort_by.rs2
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs217
-rw-r--r--clippy_lints/src/methods/unwrap_or_else_default.rs24
-rw-r--r--clippy_lints/src/minmax.rs32
-rw-r--r--clippy_lints/src/needless_for_each.rs2
-rw-r--r--clippy_lints/src/only_used_in_recursion.rs15
-rw-r--r--clippy_lints/src/operators/arithmetic.rs119
-rw-r--r--clippy_lints/src/operators/arithmetic_side_effects.rs173
-rw-r--r--clippy_lints/src/operators/mod.rs32
-rw-r--r--clippy_lints/src/panic_in_result_fn.rs2
-rw-r--r--clippy_lints/src/ptr.rs4
-rw-r--r--clippy_lints/src/ranges.rs11
-rw-r--r--clippy_lints/src/returns.rs2
-rw-r--r--clippy_lints/src/suspicious_trait_impl.rs2
-rw-r--r--clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--clippy_lints/src/unit_types/unit_arg.rs2
-rw-r--r--clippy_lints/src/unnecessary_wraps.rs2
-rw-r--r--clippy_lints/src/unwrap.rs2
-rw-r--r--clippy_lints/src/unwrap_in_result.rs6
-rw-r--r--clippy_lints/src/utils/author.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints.rs41
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs4
-rw-r--r--clippy_lints/src/vec_init_then_push.rs2
-rw-r--r--clippy_lints/src/write.rs6
65 files changed, 737 insertions, 440 deletions
diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs
index 27c2896e1e5..9464694a3b5 100644
--- a/clippy_lints/src/async_yields_async.rs
+++ b/clippy_lints/src/async_yields_async.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
                     hir_id: body.value.hir_id,
                 };
                 let typeck_results = cx.tcx.typeck_body(body_id);
-                let expr_ty = typeck_results.expr_ty(&body.value);
+                let expr_ty = typeck_results.expr_ty(body.value);
 
                 if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
                     let return_expr_span = match &body.value.kind {
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 4bcbeacf9fe..732dc2b4330 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -475,7 +475,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
 
 fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Fn(_, _, eid) = item.kind {
-        is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+        is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
     } else {
         true
     }
@@ -483,7 +483,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 
 fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
     match item.kind {
-        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
+        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
         _ => false,
     }
 }
@@ -492,7 +492,7 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
     match item.kind {
         TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
         TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
-            is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+            is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
         },
         _ => false,
     }
diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs
new file mode 100644
index 00000000000..a4b8cbb0d82
--- /dev/null
+++ b/clippy_lints/src/bool_to_int_with_if.rs
@@ -0,0 +1,125 @@
+use rustc_ast::{ExprPrecedence, LitKind};
+use rustc_hir::{Block, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, source::snippet_block_with_applicability};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Instead of using an if statement to convert a bool to an int,
+    /// this lint suggests using a `from()` function or an `as` coercion.
+    ///
+    /// ### Why is this bad?
+    /// Coercion or `from()` is idiomatic way to convert bool to a number.
+    /// Both methods are guaranteed to return 1 for true, and 0 for false.
+    ///
+    /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let condition = false;
+    /// if condition {
+    ///     1_i64
+    /// } else {
+    ///     0
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let condition = false;
+    /// i64::from(condition);
+    /// ```
+    /// or
+    /// ```rust
+    /// # let condition = false;
+    /// condition as i64;
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub BOOL_TO_INT_WITH_IF,
+    style,
+    "using if to convert bool to int"
+}
+declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
+
+impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
+    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        if !expr.span.from_expansion() {
+            check_if_else(ctx, expr);
+        }
+    }
+}
+
+fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+    if let ExprKind::If(check, then, Some(else_)) = expr.kind
+        && let Some(then_lit) = int_literal(then)
+        && let Some(else_lit) = int_literal(else_)
+        && check_int_literal_equals_val(then_lit, 1)
+        && check_int_literal_equals_val(else_lit, 0)
+    {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability);
+        let snippet_with_braces = {
+            let need_parens = should_have_parentheses(check);
+            let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")};
+            format!("{left_paren}{snippet}{right_paren}")
+        };
+
+        let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+
+        let suggestion = {
+            let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+            let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")};
+            format!(
+                "{left_curly}{ty}::from({snippet}){right_curly}"
+            )
+        }; // when used in else clause if statement should be wrapped in curly braces
+
+        span_lint_and_then(ctx,
+            BOOL_TO_INT_WITH_IF,
+            expr.span,
+            "boolean to int conversion using if",
+            |diag| {
+            diag.span_suggestion(
+                expr.span,
+                "replace with from",
+                suggestion,
+                applicability,
+            );
+            diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options"));
+        });
+    };
+}
+
+// If block contains only a int literal expression, return literal expression
+fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
+    if let ExprKind::Block(block, _) = expr.kind
+        && let Block {
+            stmts: [],       // Shouldn't lint if statements with side effects
+            expr: Some(expr),
+            ..
+        } = block
+        && let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(_, _) = lit.node
+    {
+        Some(expr)
+    } else {
+        None
+    }
+}
+
+fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool {
+    if let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(val, _) = lit.node
+        && val == expected_value
+    {
+        true
+    } else {
+        false
+    }
+}
+
+fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool {
+    check.precedence().order() < ExprPrecedence::Cast.order()
+}
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 64c5de51042..be02f328e98 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -69,7 +69,10 @@ struct NumericFallbackVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
-        Self { ty_bounds: vec![TyBound::Nothing], cx }
+        Self {
+            ty_bounds: vec![TyBound::Nothing],
+            cx,
+        }
     }
 
     /// Check whether a passed literal has potential to cause fallback or not.
@@ -126,21 +129,19 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                     }
                     return;
                 }
-            }
+            },
 
             ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
-                    for (expr, bound) in
-                        iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
-                    {
+                    for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
                         self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
                     return;
                 }
-            }
+            },
 
             ExprKind::Struct(_, fields, base) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
@@ -175,15 +176,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                         return;
                     }
                 }
-            }
+            },
 
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
                 self.check_lit(lit, ty, expr.hir_id);
                 return;
-            }
+            },
 
-            _ => {}
+            _ => {},
         }
 
         walk_expr(self, expr);
@@ -197,7 +198,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 } else {
                     self.ty_bounds.push(TyBound::Nothing);
                 }
-            }
+            },
 
             _ => self.ty_bounds.push(TyBound::Nothing),
         }
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index d1ab7fb6796..88e28018e5d 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -830,25 +830,22 @@ fn walk_parents<'tcx>(
                             )
                         {
                             return Some(Position::MethodReceiverRefImpl)
-                        } else {
-                            return Some(Position::MethodReceiver)
                         }
+                        return Some(Position::MethodReceiver);
                     }
-                    args.iter()
-                        .position(|arg| arg.hir_id == child_id)
-                        .map(|i| {
-                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
-                            if let ty::Param(param_ty) = ty.kind() {
-                                needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
-                            } else {
-                                ty_auto_deref_stability(
-                                    cx,
-                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
-                                    precedence,
-                                )
-                                .position_for_arg()
-                            }
-                        })
+                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
+                        let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+                        if let ty::Param(param_ty) = ty.kind() {
+                            needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
+                        } else {
+                            ty_auto_deref_stability(
+                                cx,
+                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+                                precedence,
+                            )
+                            .position_for_arg()
+                        }
+                    })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 4d7f4076d7b..ef9eeecc6a9 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
-    /// in generic types and the user defined `impl` maybe is more generalized or
+    /// in generic types and the user defined `impl` may be more generalized or
     /// specialized than what derive will produce. This lint can't detect the manual `impl`
     /// has exactly equal bounds, and therefore this lint is disabled for types with
     /// generic parameters.
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 512872cedc1..eb158d850fa 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
                         typeck_results: cx.tcx.typeck(item.def_id),
                         panic_span: None,
                     };
-                    fpu.visit_expr(&body.value);
+                    fpu.visit_expr(body.value);
                     lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
                 }
             },
@@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
                 typeck_results: cx.tcx.typeck(item.def_id),
                 panic_span: None,
             };
-            fpu.visit_expr(&body.value);
+            fpu.visit_expr(body.value);
             lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
         }
     }
@@ -348,7 +348,7 @@ fn lint_for_missing_headers<'tcx>(
                 if let Some(future) = cx.tcx.lang_items().future_trait();
                 let typeck = cx.tcx.typeck_body(body_id);
                 let body = cx.tcx.hir().body(body_id);
-                let ret_ty = typeck.expr_ty(&body.value);
+                let ret_ty = typeck.expr_ty(body.value);
                 if implements_trait(cx, ret_ty, future, &[]);
                 if let ty::Opaque(_, subs) = ret_ty.kind();
                 if let Some(gen) = subs.types().next();
@@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
             {
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 1342a4697b9..53bc617a4f5 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         };
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
-                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
+                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
                     // replace `|| vec![]` with `Vec::new`
                     span_lint_and_sugg(
                         cx,
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         let closure_ty = cx.typeck_results().expr_ty(expr);
 
         if_chain!(
-            if !is_adjusted(cx, &body.value);
+            if !is_adjusted(cx, body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
             if check_inputs(cx, body.params, None, args);
@@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         );
 
         if_chain!(
-            if !is_adjusted(cx, &body.value);
+            if !is_adjusted(cx, body.value);
             if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
             if check_inputs(cx, body.params, Some(receiver), args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
@@ -206,8 +206,7 @@ fn check_inputs(
             _ => false,
         }
     };
-    std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
-        .all(|(param, arg)| check_inputs(param, arg))
+    std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs
index 790eea63f58..1f69f34a229 100644
--- a/clippy_lints/src/fallible_impl_from.rs
+++ b/clippy_lints/src/fallible_impl_from.rs
@@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+                let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
                 {
@@ -110,7 +110,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
                     typeck_results: cx.tcx.typeck(impl_item.id.def_id),
                     result: Vec::new(),
                 };
-                fpu.visit_expr(&body.value);
+                fpu.visit_expr(body.value);
 
                 // if we've found one, lint
                 if !fpu.result.is_empty() {
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index 728db41d600..ba53a967880 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -238,23 +238,23 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
     if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
-        let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
-            "exp"
+        if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
+            Some("exp")
         } else if F32(2.0) == value || F64(2.0) == value {
-            "exp2"
+            Some("exp2")
         } else {
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            SUBOPTIMAL_FLOPS,
-            expr.span,
-            "exponent for bases 2 and e can be computed more accurately",
-            "consider using",
-            format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
-            Applicability::MachineApplicable,
-        );
+            None
+        } {
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "exponent for bases 2 and e can be computed more accurately",
+                "consider using",
+                format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
+                Applicability::MachineApplicable,
+            );
+        }
     }
 
     // Check argument
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index a17b23f5edc..00a4937763e 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -272,6 +272,6 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
         cx,
         mutates_static: false,
     };
-    intravisit::walk_expr(&mut v, &body.value);
+    intravisit::walk_expr(&mut v, body.value);
     v.mutates_static
 }
diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
index af520a493ed..9591405cb06 100644
--- a/clippy_lints/src/functions/result.rs
+++ b/clippy_lints/src/functions/result.rs
@@ -4,7 +4,6 @@ use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
 
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::trait_ref_of_method;
@@ -17,11 +16,12 @@ use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
 fn result_err_ty<'tcx>(
     cx: &LateContext<'tcx>,
     decl: &hir::FnDecl<'tcx>,
+    id: hir::def_id::LocalDefId,
     item_span: Span,
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
     if !in_external_macro(cx.sess(), item_span)
         && let hir::FnRetTy::Return(hir_ty) = decl.output
-        && let ty = hir_ty_to_ty(cx.tcx, hir_ty)
+        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
         && let ty::Adt(_, substs) = ty.kind()
     {
@@ -34,7 +34,7 @@ fn result_err_ty<'tcx>(
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
     if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
     {
         if cx.access_levels.is_exported(item.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -47,7 +47,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
         && trait_ref_of_method(cx, item.def_id).is_none()
     {
         if cx.access_levels.is_exported(item.def_id) {
@@ -61,7 +61,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) {
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) {
             if cx.access_levels.is_exported(item.def_id) {
                 check_result_unit_err(cx, err_ty, fn_header_span);
             }
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index a6610ade37e..feec8ec2e23 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -232,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
             return;
         }
 
-        let res_ty = cx.typeck_results().expr_ty(&body.value);
+        let res_ty = cx.typeck_results().expr_ty(body.value);
         if res_ty.is_unit() || res_ty.is_never() {
             return;
         }
@@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
                 None => return,
             }
         } else {
-            &body.value
+            body.value
         };
         lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
     }
diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs
index d55a8e1ead1..8c2c96fa105 100644
--- a/clippy_lints/src/infinite_iter.rs
+++ b/clippy_lints/src/infinite_iter.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
             MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
             Finite => {
                 return;
-            }
+            },
         };
         span_lint(cx, lint, expr.span, msg);
     }
@@ -161,7 +161,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             if method.ident.name == sym!(flat_map) && args.len() == 1 {
                 if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
                     let body = cx.tcx.hir().body(body);
-                    return is_infinite(cx, &body.value);
+                    return is_infinite(cx, body.value);
                 }
             }
             Finite
@@ -230,8 +230,10 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 }
             }
             if method.ident.name == sym!(last) && args.is_empty() {
-                let not_double_ended =
-                    cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
+                let not_double_ended = cx
+                    .tcx
+                    .get_diagnostic_item(sym::DoubleEndedIterator)
+                    .map_or(false, |id| {
                         !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
                     });
                 if not_double_ended {
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index c58df126d62..eb13d0869c0 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -1,13 +1,12 @@
 //! lint when there is a large size difference between variants on an enum
 
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
+use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{Adt, Ty};
+use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
@@ -17,7 +16,7 @@ declare_clippy_lint! {
     /// `enum`s.
     ///
     /// ### Why is this bad?
-    /// Enum size is bounded by the largest variant. Having a
+    /// Enum size is bounded by the largest variant. Having one
     /// large variant can penalize the memory layout of that enum.
     ///
     /// ### Known problems
@@ -33,8 +32,9 @@ declare_clippy_lint! {
     /// use case it may be possible to store the large data in an auxiliary
     /// structure (e.g. Arena or ECS).
     ///
-    /// The lint will ignore generic types if the layout depends on the
-    /// generics, even if the size difference will be large anyway.
+    /// The lint will ignore the impact of generic types to the type layout by
+    /// assuming every type parameter is zero-sized. Depending on your use case,
+    /// this may lead to a false positive.
     ///
     /// ### Example
     /// ```rust
@@ -83,6 +83,38 @@ struct VariantInfo {
     fields_size: Vec<FieldInfo>,
 }
 
+fn variants_size<'tcx>(
+    cx: &LateContext<'tcx>,
+    adt: AdtDef<'tcx>,
+    subst: &'tcx List<GenericArg<'tcx>>,
+) -> Vec<VariantInfo> {
+    let mut variants_size = adt
+        .variants()
+        .iter()
+        .enumerate()
+        .map(|(i, variant)| {
+            let mut fields_size = variant
+                .fields
+                .iter()
+                .enumerate()
+                .map(|(i, f)| FieldInfo {
+                    ind: i,
+                    size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
+                })
+                .collect::<Vec<_>>();
+            fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
+
+            VariantInfo {
+                ind: i,
+                size: fields_size.iter().map(|info| info.size).sum(),
+                fields_size,
+            }
+        })
+        .collect::<Vec<_>>();
+    variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+    variants_size
+}
+
 impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -92,36 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
-            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+            let (adt, subst) = match ty.kind() {
+                Adt(adt, subst) => (adt, subst),
+                _ => panic!("already checked whether this is an enum"),
+            };
             if adt.variants().len() <= 1 {
                 return;
             }
-            let mut variants_size: Vec<VariantInfo> = Vec::new();
-            for (i, variant) in adt.variants().iter().enumerate() {
-                let mut fields_size = Vec::new();
-                for (i, f) in variant.fields.iter().enumerate() {
-                    let ty = cx.tcx.type_of(f.did);
-                    // don't lint variants which have a field of generic type.
-                    match cx.layout_of(ty) {
-                        Ok(l) => {
-                            let fsize = l.size.bytes();
-                            fields_size.push(FieldInfo { ind: i, size: fsize });
-                        },
-                        Err(_) => {
-                            return;
-                        },
-                    }
-                }
-                let size: u64 = fields_size.iter().map(|info| info.size).sum();
-
-                variants_size.push(VariantInfo {
-                    ind: i,
-                    size,
-                    fields_size,
-                });
-            }
-
-            variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+            let variants_size = variants_size(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
             if difference > self.maximum_size_difference_allowed {
@@ -129,20 +139,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                 span_lint_and_then(
                     cx,
                     LARGE_ENUM_VARIANT,
-                    def.variants[variants_size[0].ind].span,
+                    item.span,
                     "large size difference between variants",
                     |diag| {
                         diag.span_label(
+                            item.span,
+                            format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)),
+                        );
+                        diag.span_label(
                             def.variants[variants_size[0].ind].span,
-                            &format!("this variant is {} bytes", variants_size[0].size),
+                            format!("the largest variant contains at least {} bytes", variants_size[0].size),
                         );
-                        diag.span_note(
+                        diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
+                            &if variants_size[1].fields_size.is_empty() {
+                                "the second-largest variant carries no data at all".to_owned()
+                            } else {
+                                format!(
+                                    "the second-largest variant contains at least {} bytes",
+                                    variants_size[1].size
+                                )
+                            },
                         );
 
                         let fields = def.variants[variants_size[0].ind].data.fields();
-                        variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
                         let mut applicability = Applicability::MaybeIncorrect;
                         if is_copy(cx, ty) || maybe_copy(cx, ty) {
                             diag.span_note(
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 3cbdaff407b..7ae8ef830fa 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -370,7 +370,8 @@ fn check_for_is_empty<'tcx>(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+    {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,12 +379,23 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
+        check_len(
+            cx,
+            span,
+            method_path.ident.name,
+            receiver,
+            args,
+            &lit.node,
+            op,
+            compare_to,
+        );
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
 }
 
+// FIXME(flip1995): Figure out how to reduce the number of arguments
+#[allow(clippy::too_many_arguments)]
 fn check_len(
     cx: &LateContext<'_>,
     span: Span,
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 134cbbf7b5c..1f85382347a 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -17,6 +17,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index fd20e016578..962e6722006 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -56,6 +56,7 @@ store.register_lints(&[
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
     blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
+    bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
     booleans::NONMINIMAL_BOOL,
     booleans::OVERLY_COMPLEX_BOOL_EXPR,
     borrow_deref_ref::BORROW_DEREF_REF,
@@ -436,7 +437,7 @@ store.register_lints(&[
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
     operators::ABSURD_EXTREME_COMPARISONS,
-    operators::ARITHMETIC,
+    operators::ARITHMETIC_SIDE_EFFECTS,
     operators::ASSIGN_OP_PATTERN,
     operators::BAD_BIT_MASK,
     operators::CMP_NAN,
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index dd1e1e1a8e3..6eb9b3d3b9b 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -50,7 +50,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
-    LintId::of(operators::ARITHMETIC),
+    LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
     LintId::of(operators::FLOAT_ARITHMETIC),
     LintId::of(operators::FLOAT_CMP_CONST),
     LintId::of(operators::INTEGER_ARITHMETIC),
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index b5cb078e7a3..05d2ec2e9e1 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -6,6 +6,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
     LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index c70aa79ac8d..e984254bf29 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -179,6 +179,7 @@ mod attrs;
 mod await_holding_invalid;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
+mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod cargo;
@@ -523,7 +524,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     #[cfg(feature = "internal")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
+            store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
             return;
         }
     }
@@ -544,8 +545,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
-    let arithmetic_allowed = conf.arithmetic_allowed.clone();
-    store.register_late_pass(move |_| Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
+    let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+    store.register_late_pass(move |_| {
+        Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
+            arithmetic_side_effects_allowed.clone(),
+        ))
+    });
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
     let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
@@ -901,6 +906,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
     store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
     store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
+    store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 5995675bd96..f2b6e0b7ef9 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(&body.value);
+        checker.visit_expr(body.value);
         if checker.lifetimes_used_in_body {
             return false;
         }
diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs
index ffcf83e4605..8ab640051b6 100644
--- a/clippy_lints/src/loops/needless_range_loop.rs
+++ b/clippy_lints/src/loops/needless_range_loop.rs
@@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
             },
             ExprKind::Closure(&Closure { body, .. }) => {
                 let body = self.cx.tcx.hir().body(body);
-                self.visit_expr(&body.value);
+                self.visit_expr(body.value);
             },
             _ => walk_expr(self, expr),
         }
diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index 2c54033f859..deb21894f36 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -356,7 +356,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
             after_loop: false,
             used_iter: false,
         };
-        v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
+        v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
         v.used_iter
     }
 }
diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs
index bc16f17b619..a3aa2e4b389 100644
--- a/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -40,7 +40,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
                                 arm.pat.span,
                                 &format!("`Err({})` matches all errors", ident_bind_name),
                                 None,
-                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
+                                "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
                             );
                         }
                     }
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 1bf1c4d1078..56bcdc01fe4 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -203,12 +203,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
             let left_pos = left_pos.as_opt_usize();
             let right_pos = right_pos.as_opt_usize();
             let len = max(
-                left_in.len() + {
-                    if left_pos.is_some() { 1 } else { 0 }
-                },
-                right_in.len() + {
-                    if right_pos.is_some() { 1 } else { 0 }
-                },
+                left_in.len() + usize::from(left_pos.is_some()),
+                right_in.len() + usize::from(right_pos.is_some()),
             );
             let mut left_pos = left_pos.unwrap_or(usize::MAX);
             let mut right_pos = right_pos.unwrap_or(usize::MAX);
diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs
index 2f117e4dcc3..22f5635a5bc 100644
--- a/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap {
         match arg.kind {
             hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
                 let closure_body = cx.tcx.hir().body(body);
-                let closure_expr = peel_blocks(&closure_body.value);
+                let closure_expr = peel_blocks(closure_body.value);
 
                 if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
                     true
diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs
index 51aec21527a..b2bc1ad5c9e 100644
--- a/clippy_lints/src/methods/chars_cmp.rs
+++ b/clippy_lints/src/methods/chars_cmp.rs
@@ -23,7 +23,7 @@ pub(super) fn check(
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
+            let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs();
 
             if *self_ty.kind() != ty::Str {
                 return false;
diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs
index f5bead387d7..7ab6b84c207 100644
--- a/clippy_lints/src/methods/clone_on_copy.rs
+++ b/clippy_lints/src/methods/clone_on_copy.rs
@@ -21,7 +21,11 @@ pub(super) fn check(
     receiver: &Expr<'_>,
     args: &[Expr<'_>],
 ) {
-    let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
+    let arg = if method_name == sym::clone && args.is_empty() {
+        receiver
+    } else {
+        return;
+    };
     if cx
         .typeck_results()
         .type_dependent_def_id(expr.hir_id)
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index 9dc839afc62..9719b2f1c51 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
         },
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&body.value);
+            let closure_expr = peel_blocks(body.value);
             let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
                 hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs
index e8442091fd3..8261ef5e1ce 100644
--- a/clippy_lints/src/methods/map_clone.rs
+++ b/clippy_lints/src/methods/map_clone.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
         then {
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
             match closure_body.params[0].pat.kind {
                 hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
                     hir::BindingAnnotation::NONE, .., name, None
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 48a9d6e7c32..41942b20ea1 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -825,8 +825,9 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
-    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
-    /// `unwrap_or_default` instead.
+    /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+    /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+    /// etc. instead.
     ///
     /// ### Why is this bad?
     /// The function will always be called and potentially
diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs
index bd8458a222e..b9593b3687d 100644
--- a/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
@@ -11,6 +11,7 @@ use super::MUT_MUTEX_LOCK;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if_chain! {
+        if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut));
         if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs
index 903fa306f93..597af853dc6 100644
--- a/clippy_lints/src/methods/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
-        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
+        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
             let argument_option = match arguments[0].kind {
                 ExprKind::Lit(ref span) => {
                     if let Spanned {
diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs
index 81c67b4ca6a..c409268de76 100644
--- a/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
             }),
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
 
             match &closure_expr.kind {
                 hir::ExprKind::MethodCall(_, receiver, [], _) => {
diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs
index 5a39b82b027..6657cdccd01 100644
--- a/clippy_lints/src/methods/option_map_or_none.rs
+++ b/clippy_lints/src/methods/option_map_or_none.rs
@@ -74,7 +74,7 @@ pub(super) fn check<'tcx>(
             if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
             let arg_snippet = snippet(cx, fn_decl_span, "..");
             let body = cx.tcx.hir().body(body);
-            if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
+            if let Some((func, [arg_char])) = reduce_unit_expression(body.value);
             if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
             if Some(id) == cx.tcx.lang_items().option_some_variant();
             then {
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 76876d86629..b43b9258c47 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -23,7 +23,8 @@ pub(super) fn check<'tcx>(
     receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
-    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
+    /// `or_insert(T::new())` or `or_insert(T::default())`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
@@ -43,7 +44,11 @@ pub(super) fn check<'tcx>(
 
         if_chain! {
             if !or_has_args;
-            if name == "unwrap_or";
+            if let Some(sugg) = match name {
+                "unwrap_or" => Some("unwrap_or_default"),
+                "or_insert" => Some("or_default"),
+                _ => None,
+            };
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
             let path = last_path_segment(qpath).ident.name;
@@ -59,7 +64,7 @@ pub(super) fn check<'tcx>(
                     method_span.with_hi(span.hi()),
                     &format!("use of `{}` followed by a call to `{}`", name, path),
                     "try this",
-                    "unwrap_or_default()".to_string(),
+                    format!("{}()", sugg),
                     Applicability::MachineApplicable,
                 );
 
@@ -83,7 +88,7 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) {
         // (path, fn_has_argument, methods, suffix)
-        static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
+        const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs
index 9c3375bf35e..851cdf54455 100644
--- a/clippy_lints/src/methods/suspicious_map.rs
+++ b/clippy_lints/src/methods/suspicious_map.rs
@@ -15,9 +15,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi
         if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
         if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
         let closure_body = cx.tcx.hir().body(body_id);
-        if !cx.typeck_results().expr_ty(&closure_body.value).is_unit();
+        if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
         then {
-            if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) {
+            if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
                 // A variable is used mutably inside of the closure. Suppress the lint.
                 if !map_mutated_vars.is_empty() {
                     return;
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
index bafa6fc584d..4e8c201f470 100644
--- a/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -21,14 +21,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
     if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
         let body = cx.tcx.hir().body(body);
         let arg_id = body.params[0].pat.hir_id;
-        let mutates_arg =
-            mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
-        let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, &body.value);
+        let mutates_arg = mutated_variables(body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
+        let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
 
-        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
+        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value);
 
         let mut return_visitor = ReturnVisitor::new(cx, arg_id);
-        return_visitor.visit_expr(&body.value);
+        return_visitor.visit_expr(body.value);
         found_mapping |= return_visitor.found_mapping;
         found_filtering |= return_visitor.found_filtering;
 
@@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         let sugg = if !found_filtering {
             if name == "filter_map" { "map" } else { "map(..).next()" }
         } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
-            match cx.typeck_results().expr_ty(&body.value).kind() {
+            match cx.typeck_results().expr_ty(body.value).kind() {
                 ty::Adt(adt, subst)
                     if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
                 {
diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs
index c3531d4d051..c17ef6809f9 100644
--- a/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/clippy_lints/src/methods/unnecessary_fold.rs
@@ -31,7 +31,7 @@ pub(super) fn check(
             // Extract the body of the closure passed to fold
             if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
 
             // Check if the closure body is of the form `acc <op> some_expr(x)`
             if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs
index 6f25acca1de..ed5a75b0f3c 100644
--- a/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -131,7 +131,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
         ] = &closure_body.params;
         if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
         if method_path.ident.name == sym::cmp;
-        if is_trait_method(cx, &closure_body.value, sym::Ord);
+        if is_trait_method(cx, closure_body.value, sym::Ord);
         then {
             let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                 left_expr,
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 85da97a39f9..763bfafecef 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -1,21 +1,25 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
+use crate::rustc_middle::ty::Subst;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{
-    get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs,
-};
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::visitors::find_all_ret_expressions;
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::EarlyBinder;
+use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_typeck::check::{FnCtxt, Inherited};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
@@ -34,7 +38,7 @@ pub fn check<'tcx>(
         then {
             if is_cloned_or_copied(cx, method_name, method_def_id) {
                 unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
-            } else if is_to_owned_like(cx, method_name, method_def_id) {
+            } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
                 // At this point, we know the call is of a `to_owned`-like function. The functions
                 // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
                 // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
@@ -246,17 +250,12 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+        if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
-        let index = if let Some(call_receiver) = call_receiver {
-            std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
-        } else {
-            call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
-        };
-        if let Some(i) = index;
+        if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
-        if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
+        if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
         if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
         if let [trait_predicate] = trait_predicates
             .iter()
@@ -264,52 +263,13 @@ fn check_other_call_arg<'tcx>(
             .collect::<Vec<_>>()[..];
         if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
         if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+        if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
-        // If the callee has type parameters, they could appear in `projection_predicate.ty` or the
-        // types of `trait_predicate.trait_ref.substs`.
-        if if trait_predicate.def_id() == deref_trait_id {
-            if let [projection_predicate] = projection_predicates[..] {
-                let normalized_ty =
-                    cx.tcx
-                        .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
-                implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
-                        .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack())
-            } else {
-                false
-            }
-        } else if trait_predicate.def_id() == as_ref_trait_id {
-            let composed_substs = compose_substs(
-                cx,
-                &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
-                call_substs,
-            );
-            // if `expr` is a `String` and generic target is [u8], skip
-            // (https://github.com/rust-lang/rust-clippy/issues/9317).
-            if let [subst] = composed_substs[..]
-                && let GenericArgKind::Type(arg_ty) = subst.unpack()
-                && arg_ty.is_slice()
-                && let inner_ty = arg_ty.builtin_index().unwrap()
-                && let ty::Uint(ty::UintTy::U8) = inner_ty.kind()
-                && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs()
-                && is_type_diagnostic_item(cx, self_ty, sym::String) {
-                false
-            } else {
-                implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
-            }
-        } else {
-            false
-        };
+        if can_change_type(cx, maybe_arg, receiver_ty);
         // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
         // `Target = T`.
         if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
         let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
-        // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then
-        // `T` must not be instantiated with a reference
-        // (https://github.com/rust-lang/rust-clippy/issues/8507).
-        if (n_refs == 0 && !receiver_ty.is_ref())
-            || trait_predicate.def_id() != as_ref_trait_id
-            || !fn_sig.output().contains(input);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -359,11 +319,11 @@ fn get_callee_substs_and_args<'tcx>(
         }
     }
     if_chain! {
-        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
+        if let ExprKind::MethodCall(_, recv, args, _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         then {
             let substs = cx.typeck_results().node_substs(expr.hir_id);
-            return Some((method_def_id, substs, Some(receiver), args));
+            return Some((method_def_id, substs, Some(recv), args));
         }
     }
     None
@@ -395,22 +355,103 @@ fn get_input_traits_and_projections<'tcx>(
     (trait_predicates, projection_predicates)
 }
 
-/// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs<'tcx>(
-    cx: &LateContext<'tcx>,
-    left: &[GenericArg<'tcx>],
-    right: SubstsRef<'tcx>,
-) -> Vec<GenericArg<'tcx>> {
-    left.iter()
-        .map(|arg| {
-            if let GenericArgKind::Type(arg_ty) = arg.unpack() {
-                let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
-                GenericArg::from(normalized_ty)
-            } else {
-                *arg
+fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
+    for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        match node {
+            Node::Stmt(_) => return true,
+            Node::Block(..) => continue,
+            Node::Item(item) => {
+                if let ItemKind::Fn(_, _, body_id) = &item.kind
+                && let output_ty = return_ty(cx, item.hir_id())
+                && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
+                && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
+                    let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id());
+                    fn_ctxt.can_coerce(ty, output_ty)
+                }) {
+                    if has_lifetime(output_ty) && has_lifetime(ty) {
+                        return false;
+                    }
+                    let body = cx.tcx.hir().body(*body_id);
+                    let body_expr = &body.value;
+                    let mut count = 0;
+                    return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 });
+                }
             }
-        })
-        .collect()
+            Node::Expr(parent_expr) => {
+                if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
+                {
+                    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+                    if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
+                        && let Some(param_ty) = fn_sig.inputs().get(arg_index)
+                        && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+                    {
+                        if fn_sig
+                            .inputs()
+                            .iter()
+                            .enumerate()
+                            .filter(|(i, _)| *i != arg_index)
+                            .any(|(_, ty)| ty.contains(*param_ty))
+                        {
+                            return false;
+                        }
+
+                        let mut trait_predicates = cx.tcx.param_env(callee_def_id)
+                            .caller_bounds().iter().filter(|predicate| {
+                            if let PredicateKind::Trait(trait_predicate) =  predicate.kind().skip_binder()
+                                && trait_predicate.trait_ref.self_ty() == *param_ty {
+                                    true
+                                } else {
+                                false
+                            }
+                        });
+
+                        let new_subst = cx.tcx.mk_substs(
+                            call_substs.iter()
+                                .enumerate()
+                                .map(|(i, t)|
+                                     if i == (*param_index as usize) {
+                                         GenericArg::from(ty)
+                                     } else {
+                                         t
+                                     }));
+
+                        if trait_predicates.any(|predicate| {
+                            let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
+                            let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+                            !cx.tcx
+                                .infer_ctxt()
+                                .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+                        }) {
+                            return false;
+                        }
+
+                        let output_ty = fn_sig.output();
+                        if output_ty.contains(*param_ty) {
+                            if let Ok(new_ty)  = cx.tcx.try_subst_and_normalize_erasing_regions(
+                                new_subst, cx.param_env, output_ty) {
+                                expr = parent_expr;
+                                ty = new_ty;
+                                continue;
+                            }
+                            return false;
+                        }
+
+                        return true;
+                    }
+                } else if let ExprKind::Block(..) = parent_expr.kind {
+                    continue;
+                }
+                return false;
+            },
+            _ => return false,
+        }
+    }
+
+    false
+}
+
+fn has_lifetime(ty: Ty<'_>) -> bool {
+    ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
@@ -421,10 +462,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
-        || is_to_string(cx, method_name, method_def_id)
+        || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
 }
 
 /// Returns true if the named method is `Cow::into_owned`.
@@ -432,7 +473,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D
     method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
 }
 
-/// Returns true if the named method is `ToString::to_string`.
-fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString)
+/// Returns true if the named method is `ToString::to_string` and it's called on a type that
+/// is string-like i.e. implements `AsRef<str>` or `Deref<str>`.
+fn is_to_string_on_string_like<'a>(
+    cx: &LateContext<'_>,
+    call_expr: &'a Expr<'a>,
+    method_name: Symbol,
+    method_def_id: DefId,
+) -> bool {
+    if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) {
+        return false;
+    }
+
+    if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
+        && let [generic_arg] = substs.as_slice()
+        && let GenericArgKind::Type(ty) = generic_arg.unpack()
+        && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+        && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+        && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) ||
+            implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
+            true
+        } else {
+            false
+        }
 }
diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs
index f3af281d6ca..045f739e64d 100644
--- a/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ b/clippy_lints/src/methods/unwrap_or_else_default.rs
@@ -5,10 +5,11 @@ use clippy_utils::{
     diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
     ty::is_type_diagnostic_item,
 };
+use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{sym, symbol};
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(
 
     if_chain! {
         if is_option || is_result;
-        if is_default_equivalent_call(cx, u_arg);
+        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -44,3 +45,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+            && ident == &symbol::Ident::from_str("to_string")
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index 44b21e7b080..4d8579135fc 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -1,7 +1,6 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{match_trait_method, paths};
-use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -84,19 +83,16 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
             }
         },
         ExprKind::MethodCall(path, receiver, args @ [_], _) => {
-            if_chain! {
-                if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
-                then {
-                    if path.ident.name == sym!(max) {
-                        fetch_const(cx, Some(receiver), args, MinMax::Max)
-                    } else if path.ident.name == sym!(min) {
-                        fetch_const(cx, Some(receiver), args, MinMax::Min)
-                    } else {
-                        None
-                    }
+            if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) {
+                if path.ident.name == sym!(max) {
+                    fetch_const(cx, Some(receiver), args, MinMax::Max)
+                } else if path.ident.name == sym!(min) {
+                    fetch_const(cx, Some(receiver), args, MinMax::Min)
                 } else {
                     None
                 }
+            } else {
+                None
             }
         },
         _ => None,
@@ -109,18 +105,18 @@ fn fetch_const<'a>(
     args: &'a [Expr<'a>],
     m: MinMax,
 ) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    let mut args = receiver.into_iter().chain(args.into_iter());
-    let arg0 = args.next()?;
-    let arg1 = args.next()?;
+    let mut args = receiver.into_iter().chain(args);
+    let first_arg = args.next()?;
+    let second_arg = args.next()?;
     if args.next().is_some() {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
+    constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
+        || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
         |c| {
-            if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
+            if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
                 // otherwise ignore
-                Some((m, c, arg1))
+                Some((m, c, second_arg))
             } else {
                 None
             }
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs
index f8cc3fbb3cd..3233d87c073 100644
--- a/clippy_lints/src/needless_for_each.rs
+++ b/clippy_lints/src/needless_for_each.rs
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             if let ExprKind::Block(..) = body.value.kind;
             then {
                 let mut ret_collector = RetCollector::default();
-                ret_collector.visit_expr(&body.value);
+                ret_collector.visit_expr(body.value);
 
                 // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
                 if ret_collector.ret_in_loop {
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 17d5fa2152b..6217110a1f3 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::{self, ConstKind};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -234,11 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
             })) => (
                 def_id.to_def_id(),
                 FnKind::TraitFn,
-                if sig.decl.implicit_self.has_implicit_self() {
-                    1
-                } else {
-                    0
-                },
+                usize::from(sig.decl.implicit_self.has_implicit_self()),
             ),
             Some(Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(ref sig, _),
@@ -253,11 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                     (
                         trait_item_id,
                         FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
-                        if sig.decl.implicit_self.has_implicit_self() {
-                            1
-                        } else {
-                            0
-                        },
+                        usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
                     (def_id.to_def_id(), FnKind::Fn, 0)
@@ -310,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                                     && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
                             }) =>
                         {
-                            if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
+                            if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
                                 param.uses.push(Usage::new(span, idx));
                             }
                             return;
diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic.rs
deleted file mode 100644
index 800cf249f5c..00000000000
--- a/clippy_lints/src/operators/arithmetic.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-#![allow(
-    // False positive
-    clippy::match_same_arms
-)]
-
-use super::ARITHMETIC;
-use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Span;
-
-const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"];
-
-#[derive(Debug)]
-pub struct Arithmetic {
-    allowed: FxHashSet<String>,
-    // Used to check whether expressions are constants, such as in enum discriminants and consts
-    const_span: Option<Span>,
-    expr_span: Option<Span>,
-}
-
-impl_lint_pass!(Arithmetic => [ARITHMETIC]);
-
-impl Arithmetic {
-    #[must_use]
-    pub fn new(mut allowed: FxHashSet<String>) -> Self {
-        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
-        Self {
-            allowed,
-            const_span: None,
-            expr_span: None,
-        }
-    }
-
-    /// Checks if the given `expr` has any of the inner `allowed` elements.
-    fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-        self.allowed.contains(
-            cx.typeck_results()
-                .expr_ty(expr)
-                .to_string()
-                .split('<')
-                .next()
-                .unwrap_or_default(),
-        )
-    }
-
-    fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
-        self.expr_span = Some(expr.span);
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if self.expr_span.is_some() {
-            return;
-        }
-        if let Some(span) = self.const_span && span.contains(expr.span) {
-            return;
-        }
-        match &expr.kind {
-            hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
-                let (
-                    hir::BinOpKind::Add
-                    | hir::BinOpKind::Sub
-                    | hir::BinOpKind::Mul
-                    | hir::BinOpKind::Div
-                    | hir::BinOpKind::Rem
-                    | hir::BinOpKind::Shl
-                    | hir::BinOpKind::Shr
-                ) = op.node else {
-                    return;
-                };
-                if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
-                    return;
-                }
-                self.issue_lint(cx, expr);
-            },
-            hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
-                // CTFE already takes care of things like `-1` that do not overflow.
-                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
-                    self.issue_lint(cx, expr);
-                }
-            },
-            _ => {},
-        }
-    }
-
-    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
-        match cx.tcx.hir().body_owner_kind(body_owner) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
-                let body_span = cx.tcx.def_span(body_owner);
-                if let Some(span) = self.const_span && span.contains(body_span) {
-                    return;
-                }
-                self.const_span = Some(body_span);
-            },
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {},
-        }
-    }
-
-    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_span = cx.tcx.hir().span(body_owner);
-        if let Some(span) = self.const_span && span.contains(body_span) {
-            return;
-        }
-        self.const_span = None;
-    }
-
-    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if Some(expr.span) == self.expr_span {
-            self.expr_span = None;
-        }
-    }
-}
diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
new file mode 100644
index 00000000000..83b69fbb311
--- /dev/null
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -0,0 +1,173 @@
+#![allow(
+    // False positive
+    clippy::match_same_arms
+)]
+
+use super::ARITHMETIC_SIDE_EFFECTS;
+use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::source_map::{Span, Spanned};
+
+const HARD_CODED_ALLOWED: &[&str] = &[
+    "f32",
+    "f64",
+    "std::num::Saturating",
+    "std::string::String",
+    "std::num::Wrapping",
+];
+
+#[derive(Debug)]
+pub struct ArithmeticSideEffects {
+    allowed: FxHashSet<String>,
+    // Used to check whether expressions are constants, such as in enum discriminants and consts
+    const_span: Option<Span>,
+    expr_span: Option<Span>,
+}
+
+impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
+
+impl ArithmeticSideEffects {
+    #[must_use]
+    pub fn new(mut allowed: FxHashSet<String>) -> Self {
+        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+        Self {
+            allowed,
+            const_span: None,
+            expr_span: None,
+        }
+    }
+
+    /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that
+    /// won't overflow.
+    fn has_valid_assign_op(op: &Spanned<hir::BinOpKind>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        if !Self::is_literal_integer(rhs, rhs_refs) {
+            return false;
+        }
+        if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node
+            && let hir::ExprKind::Lit(ref lit) = rhs.kind
+            && let ast::LitKind::Int(1, _) = lit.node
+        {
+            return true;
+        }
+        false
+    }
+
+    /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment
+    /// already handled by the CTFE.
+    fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs)
+    }
+
+    /// Checks if the given `expr` has any of the inner `allowed` elements.
+    fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+        self.allowed.contains(
+            cx.typeck_results()
+                .expr_ty(expr)
+                .to_string()
+                .split('<')
+                .next()
+                .unwrap_or_default(),
+        )
+    }
+
+    /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references.
+    fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool {
+        let is_integral = expr_refs.is_integral();
+        let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_));
+        is_integral && is_literal
+    }
+
+    fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+        span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected");
+        self.expr_span = Some(expr.span);
+    }
+
+    /// Manages when the lint should be triggered. Operations in constant environments, hard coded
+    /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+    fn manage_bin_ops(
+        &mut self,
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        op: &Spanned<hir::BinOpKind>,
+        lhs: &hir::Expr<'_>,
+        rhs: &hir::Expr<'_>,
+    ) {
+        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+            return;
+        }
+        if !matches!(
+            op.node,
+            hir::BinOpKind::Add
+                | hir::BinOpKind::Sub
+                | hir::BinOpKind::Mul
+                | hir::BinOpKind::Div
+                | hir::BinOpKind::Rem
+                | hir::BinOpKind::Shl
+                | hir::BinOpKind::Shr
+        ) {
+            return;
+        };
+        if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
+            return;
+        }
+        let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs();
+        let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs();
+        let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs);
+        if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) {
+            return;
+        }
+        self.issue_lint(cx, expr);
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
+            return;
+        }
+        match &expr.kind {
+            hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
+                self.manage_bin_ops(cx, expr, op, lhs, rhs);
+            },
+            hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
+                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
+                    self.issue_lint(cx, expr);
+                }
+            },
+            _ => {},
+        }
+    }
+
+    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+        let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+            let body_span = cx.tcx.hir().span_with_body(body_owner);
+            if let Some(span) = self.const_span && span.contains(body_span) {
+                return;
+            }
+            self.const_span = Some(body_span);
+        }
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_span = cx.tcx.hir().span(body_owner);
+        if let Some(span) = self.const_span && span.contains(body_span) {
+            return;
+        }
+        self.const_span = None;
+    }
+
+    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if Some(expr.span) == self.expr_span {
+            self.expr_span = None;
+        }
+    }
+}
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index bb6d99406b4..c32b4df4f75 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -21,7 +21,7 @@ mod ptr_eq;
 mod self_assignment;
 mod verbose_bit_mask;
 
-pub(crate) mod arithmetic;
+pub(crate) mod arithmetic_side_effects;
 
 use rustc_hir::{Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -61,25 +61,29 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for any kind of arithmetic operation of any type.
+    /// Checks any kind of arithmetic operation of any type.
     ///
     /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
     /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-    /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
-    /// away.
+    /// or can panic (`/`, `%`).
+    ///
+    /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant
+    /// environments, allowed types and non-constant operations that won't overflow are ignored.
     ///
     /// ### Why is this bad?
-    /// Integer overflow will trigger a panic in debug builds or will wrap in
-    /// release mode. Division by zero will cause a panic in either mode. In some applications one
-    /// wants explicitly checked, wrapping or saturating arithmetic.
+    /// For integers, overflow will trigger a panic in debug builds or wrap the result in
+    /// release mode; division by zero will cause a panic in either mode. As a result, it is
+    /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
     ///
     /// #### Example
     /// ```rust
-    /// # let a = 0;
-    /// a + 1;
+    /// // `n` can be any number, including `i32::MAX`.
+    /// fn foo(n: i32) -> i32 {
+    ///   n + 1
+    /// }
     /// ```
     ///
-    /// Third-party types also tend to overflow.
+    /// Third-party types can also overflow or present unwanted side-effects.
     ///
     /// #### Example
     /// ```ignore,rust
@@ -88,11 +92,11 @@ declare_clippy_lint! {
     /// ```
     ///
     /// ### Allowed types
-    /// Custom allowed types can be specified through the "arithmetic-allowed" filter.
+    /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
     #[clippy::version = "1.64.0"]
-    pub ARITHMETIC,
+    pub ARITHMETIC_SIDE_EFFECTS,
     restriction,
-    "any arithmetic expression that could overflow or panic"
+    "any arithmetic expression that can cause side effects like overflows or panics"
 }
 
 declare_clippy_lint! {
@@ -785,7 +789,7 @@ pub struct Operators {
 }
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
-    ARITHMETIC,
+    ARITHMETIC_SIDE_EFFECTS,
     INTEGER_ARITHMETIC,
     FLOAT_ARITHMETIC,
     ASSIGN_OP_PATTERN,
diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs
index 21acf003d92..4aa0d9227ab 100644
--- a/clippy_lints/src/panic_in_result_fn.rs
+++ b/clippy_lints/src/panic_in_result_fn.rs
@@ -69,7 +69,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
         }
         true
     })
-    .visit_expr(&body.value);
+    .visit_expr(body.value);
     if !panics.is_empty() {
         span_lint_and_then(
             cx,
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 0028e0bc6c5..41d1baba64f 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -507,7 +507,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
         if let Some(args) = args
             && !args.is_empty()
             && body.map_or(true, |body| {
-                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value)
+                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value)
             })
         {
             span_lint_and_then(
@@ -664,7 +664,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
         results,
         skip_count,
     };
-    v.visit_expr(&body.value);
+    v.visit_expr(body.value);
     v.results
 }
 
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index 490f345d297..918d624eec6 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -350,6 +350,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
 // exclusive range plus one: `x..(y+1)`
 fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range {
             start,
             end: Some(end),
@@ -357,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
         }) = higher::Range::hir(expr);
         if let Some(y) = y_plus_one(cx, end);
         then {
-            let span = if expr.span.from_expansion() {
-                expr.span
-                    .ctxt()
-                    .outer_expn_data()
-                    .call_site
-            } else {
-                expr.span
-            };
+            let span = expr.span;
             span_lint_and_then(
                 cx,
                 RANGE_PLUS_ONE,
@@ -399,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 // inclusive range minus one: `x..=(y-1)`
 fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
         if let Some(y) = y_minus_one(cx, end);
         then {
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 1926661c596..91553240e3c 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
+                check_final_expr(cx, body.value, Some(body.value.span), replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(block, _) = body.value.kind {
diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs
index 4294464dbf6..6add20c1fb7 100644
--- a/clippy_lints/src/suspicious_trait_impl.rs
+++ b/clippy_lints/src/suspicious_trait_impl.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
             ]
                 .iter()
                 .find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t)));
-            if count_binops(&body.value) == 1;
+            if count_binops(body.value) == 1;
             then {
                 span_lint(
                     cx,
diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs
index 851eef7b332..c0a4f3fbacd 100644
--- a/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/clippy_lints/src/unit_return_expecting_ord.rs
@@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
             let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
             for (i, trait_name) in arg_indices {
                 if i < args.len() {
-                    match check_arg(cx, &args[i]) {
+                    match check_arg(cx, args[i]) {
                         Some((span, None)) => {
                             span_lint(
                                 cx,
diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs
index 7ffb53dcf45..a6f777abc6e 100644
--- a/clippy_lints/src/unit_types/unit_arg.rs
+++ b/clippy_lints/src/unit_types/unit_arg.rs
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         })
         .collect::<Vec<_>>();
     if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
-        lint_unit_args(cx, expr, &args_to_recover.as_slice());
+        lint_unit_args(cx, expr, args_to_recover.as_slice());
     }
 }
 
diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs
index a5afbb8ff9d..2c40827db0e 100644
--- a/clippy_lints/src/unnecessary_wraps.rs
+++ b/clippy_lints/src/unnecessary_wraps.rs
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
 
         // Check if all return expression respect the following condition and collect them.
         let mut suggs = Vec::new();
-        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
+        let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| {
             if_chain! {
                 if !ret_expr.span.from_expansion();
                 // Check if a function call.
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index 9092156be15..7e451b7b7a4 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -160,7 +160,7 @@ fn collect_unwrap_info<'tcx>(
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
             then {
-                assert!(args.len() == 0);
+                assert!(args.is_empty());
                 let unwrappable = match name {
                     "is_some" | "is_ok" => true,
                     "is_err" | "is_none" => false,
diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs
index b3ca15f7648..46020adcaa2 100644
--- a/clippy_lints/src/unwrap_in_result.rs
+++ b/clippy_lints/src/unwrap_in_result.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -114,7 +114,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
             typeck_results: cx.tcx.typeck(impl_item.def_id),
             result: Vec::new(),
         };
-        fpu.visit_expr(&body.value);
+        fpu.visit_expr(body.value);
 
         // if we've found one, lint
         if !fpu.result.is_empty() {
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 1489c96d9e9..4003fff27c0 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -142,7 +142,7 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
     let hir = cx.tcx.hir();
     if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) {
         check_node(cx, hir_id, |v| {
-            v.expr(&v.bind("expr", &hir.body(body_id).value));
+            v.expr(&v.bind("expr", hir.body(body_id).value));
         });
     }
 }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 84e65d5fa0b..a8500beb257 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -208,7 +208,7 @@ define_Conf! {
     /// Lint: Arithmetic.
     ///
     /// Suppress checking of the passed type names.
-    (arithmetic_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+    (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index ae1c11ef83c..17d9a041857 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -505,7 +505,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                             .hir_id(),
                     ),
                 );
-                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
+                collector.visit_expr(cx.tcx.hir().body(body_id).value);
             }
         }
     }
@@ -653,7 +653,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(fn_name.as_str());
             let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
@@ -685,9 +685,8 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
         let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
         if_chain! {
             if let ["expn_data", "outer_expn"] = method_names.as_slice();
-            let args = arg_lists[1];
-            if args.len() == 1;
-            let self_arg = &args.0;
+            let (self_arg, args)= arg_lists[1];
+            if args.is_empty();
             let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
@@ -734,30 +733,30 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
             if and_then_args.len() == 5;
             if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
             let body = cx.tcx.hir().body(body);
-            let only_expr = peel_blocks_with_stmt(&body.value);
-            if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind;
-            if let ExprKind::Path(..) = span_call_args[0].kind;
+            let only_expr = peel_blocks_with_stmt(body.value);
+            if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
+            if let ExprKind::Path(..) = recv.kind;
             then {
                 let and_then_snippets = get_and_then_snippets(cx, and_then_args);
                 let mut sle = SpanlessEq::new(cx).deny_side_effects();
                 match ps.ident.as_str() {
-                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
+                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
                         suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
                     },
-                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
-                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
+                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
                         suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
                     },
-                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
-                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
+                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
                         suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
                     },
                     "help" => {
-                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
                         suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
                     }
                     "note" => {
-                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
                         suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
                     }
                     _  => (),
@@ -798,9 +797,9 @@ fn span_suggestion_snippets<'a, 'hir>(
     cx: &LateContext<'_>,
     span_call_args: &'hir [Expr<'hir>],
 ) -> SpanSuggestionSnippets<'a> {
-    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
-    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
-    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
+    let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+    let sugg_snippet = snippet(cx, span_call_args[2].span, "..");
+    let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable");
 
     SpanSuggestionSnippets {
         help: help_snippet,
@@ -954,7 +953,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
                 if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
                     if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
                         let body = cx.tcx.hir().body(body_id);
-                        return path_to_matched_type(cx, &body.value);
+                        return path_to_matched_type(cx, body.value);
                     }
                 }
             },
@@ -1046,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
             if el_ty.is_str();
             let body = cx.tcx.hir().body(body_id);
             let typeck_results = cx.tcx.typeck_body(body_id);
-            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value);
+            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
             let path: Vec<&str> = path.iter().map(|x| {
                     if let Constant::Str(s) = x {
                         s.as_str()
@@ -1177,7 +1176,7 @@ impl InterningDefinedSymbol {
         };
         if_chain! {
             // is a method call
-            if let ExprKind::MethodCall(_, [item], _) = call.kind;
+            if let ExprKind::MethodCall(_, item, [], _) = call.kind;
             if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
             let ty = cx.typeck_results().expr_ty(item);
             // ...on either an Ident or a Symbol
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index b1148bccc2a..342f627e382 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1145,8 +1145,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
                     self.add_single_span_suggestion();
                 }
             },
-            ExprKind::MethodCall(path, arg, _arg_span) => {
-                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0]));
+            ExprKind::MethodCall(path, recv, _, _arg_span) => {
+                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
                 if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) {
                     let called_method = path.ident.name.as_str().to_string();
                     for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS {
diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index 8425837fd73..bd5be0c9d7e 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -86,7 +86,7 @@ impl VecPushSearcher {
                 },
                 ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
                     let mut last_place = parent;
-                    while let Some(parent) = get_parent_expr(cx, parent) {
+                    while let Some(parent) = get_parent_expr(cx, last_place) {
                         if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
                             || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
                         {
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 347165d9704..640a09a7a91 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -805,7 +805,11 @@ fn check_newlines(fmtstr: &StrLit) -> bool {
     let contents = fmtstr.symbol.as_str();
 
     let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
-        let c = c.unwrap();
+        let c = match c {
+            Ok(c) => c,
+            Err(e) if !e.is_fatal() => return,
+            Err(e) => panic!("{:?}", e),
+        };
 
         if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
             should_lint = true;