about summary refs log tree commit diff
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2023-05-05 17:45:49 +0200
committerPhilipp Krones <hello@philkrones.com>2023-05-05 17:45:49 +0200
commit4cb05193fbbeee19c8448bf3c83d47e2e8915a4e (patch)
tree71917418e90ed12f35ddb3e407c28392e3b2c437 /src/tools/clippy/clippy_lints
parentdd9a7bf848e412c81e3045245acbd5a01641a610 (diff)
parent371120bdbf58a331db5dcfb2d9cddc040f486de8 (diff)
downloadrust-4cb05193fbbeee19c8448bf3c83d47e2e8915a4e.tar.gz
rust-4cb05193fbbeee19c8448bf3c83d47e2e8915a4e.zip
Merge commit '371120bdbf58a331db5dcfb2d9cddc040f486de8' into clippyup
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs8
53 files changed, 477 insertions, 119 deletions
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 18e8bf77225..37e1e6a742f 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index b984132acf5..add73d0aeee 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -2,7 +2,8 @@ use ast::AttrStyle;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast as ast;
 use rustc_errors::Applicability;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute {
     // Separate each crate's features.
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
         if_chain! {
+            if !in_external_macro(cx.sess(), attr.span);
             if cx.tcx.features().lint_reasons;
             if let AttrStyle::Outer = attr.style;
             if let Some(ident) = attr.ident();
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d74bd57fe45..cfeb75eed3b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -638,7 +638,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.66.0"]
     pub AS_PTR_CAST_MUT,
     nursery,
-    "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+    "casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 7e23318076c..804ae841100 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -141,9 +141,9 @@ fn lint_unnecessary_cast(
 
 fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
     match expr.kind {
-        ExprKind::Lit(ref lit) => Some(lit),
+        ExprKind::Lit(lit) => Some(lit),
         ExprKind::Unary(UnOp::Neg, e) => {
-            if let ExprKind::Lit(ref lit) = e.kind {
+            if let ExprKind::Lit(lit) = e.kind {
                 Some(lit)
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 970f5004993..1c321f46e2d 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
-            // Ignore eq_expr side effects iff one of the expressin kind is a method call
+            // Ignore eq_expr side effects iff one of the expression kind is a method call
             // and the caller is not a mutable, including inner mutable type.
             if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
                 if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index fa726a64937..79d0f6f3607 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::dbg_macro::DBG_MACRO_INFO,
     crate::default::DEFAULT_TRAIT_ACCESS_INFO,
     crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
+    crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,
     crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
     crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
     crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
@@ -249,6 +250,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::MANUAL_FIND_INFO,
     crate::loops::MANUAL_FLATTEN_INFO,
     crate::loops::MANUAL_MEMCPY_INFO,
+    crate::loops::MANUAL_WHILE_LET_SOME_INFO,
     crate::loops::MISSING_SPIN_LOOP_INFO,
     crate::loops::MUT_RANGE_BOUND_INFO,
     crate::loops::NEEDLESS_RANGE_LOOP_INFO,
@@ -445,6 +447,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
     crate::needless_bool::BOOL_COMPARISON_INFO,
     crate::needless_bool::NEEDLESS_BOOL_INFO,
+    crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..e529d81a7e9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -0,0 +1,72 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
+use hir::{def::Res, ExprKind};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for construction on unit struct using `default`.
+    ///
+    /// ### Why is this bad?
+    /// This adds code complexity and an unnecessary function call.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// #[derive(Default)]
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData::default()
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData
+    /// };
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+    complexity,
+    "unit structs can be contructed without calling `default`"
+}
+declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
+
+impl LateLintPass<'_> for DefaultConstructedUnitStructs {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if_chain!(
+            // make sure we have a call to `Default::default`
+            if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
+            if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
+            if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
+            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // make sure we have a struct with no fields (unit struct)
+            if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
+            if def.is_struct();
+            if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
+            if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+                    expr.span.with_lo(qpath.qself_span().hi()),
+                    "use of `default` to create a unit struct",
+                    "remove this call to `default`",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+            }
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 6615f9c9953..a51a8ee09f6 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -92,10 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
                     if trait_item.id.owner_id.def_id == fn_def_id {
                         // be sure we have `self` parameter in this function
                         if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
-                            trait_self_ty = Some(
-                                TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
-                                    .self_ty(),
-                            );
+                            trait_self_ty =
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
                         }
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 6fee7fb308c..93bf50fd5e7 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
         let ty = cx.typeck_results().expr_ty(expr);
         if_chain! {
             if let ty::Float(fty) = *ty.kind();
-            if let hir::ExprKind::Lit(ref lit) = expr.kind;
+            if let hir::ExprKind::Lit(lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
             then {
                 let sym_str = sym.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index f95b628e6c3..a1a2c398a8a 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -2,9 +2,10 @@ use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // All of these operations are currently not const.
+        // All of these operations are currently not const and are in std.
         if in_constant(cx, expr.hir_id) {
             return;
         }
@@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
         if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
-            if recv_ty.is_floating_point() {
+            if recv_ty.is_floating_point() && !is_no_std_crate(cx) {
                 match path.ident.name.as_str() {
                     "ln" => check_ln1p(cx, expr, receiver),
                     "log" => check_log_base(cx, expr, receiver, args),
@@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
                 }
             }
         } else {
-            check_expm1(cx, expr);
-            check_mul_add(cx, expr);
-            check_custom_abs(cx, expr);
-            check_log_division(cx, expr);
+            if !is_no_std_crate(cx) {
+                check_expm1(cx, expr);
+                check_mul_add(cx, expr);
+                check_custom_abs(cx, expr);
+                check_log_division(cx, expr);
+            }
             check_radians(cx, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index bd66ace4500..10ce2a0f0c7 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
                         );
                     }
 
-                    let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+                    let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
                     if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
                         diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index e5945939e60..b244b913314 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
     };
 
     // Body must be &(mut) <self_data>.name
-    // self_data is not neccessarilly self, to also lint sub-getters, etc…
+    // self_data is not necessarily self, to also lint sub-getters, etc…
 
     let block_expr = if_chain! {
         if let ExprKind::Block(block,_) = body.value.kind;
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ac2d253fe83..ee10334c67f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -252,6 +252,11 @@ declare_clippy_lint! {
     /// A `Result` is at least as large as the `Err`-variant. While we
     /// expect that variant to be seldomly used, the compiler needs to reserve
     /// and move that much memory every single time.
+    /// Furthermore, errors are often simply passed up the call-stack, making
+    /// use of the `?`-operator and its type-conversion mechanics. If the
+    /// `Err`-variant further up the call-stack stores the `Err`-variant in
+    /// question (as library code often does), it itself needs to be at least
+    /// as large, propagating the problem.
     ///
     /// ### Known problems
     /// The size determined by Clippy is platform-dependent.
@@ -330,7 +335,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints when `impl Trait` is being used in a function's paremeters.
+    /// Lints when `impl Trait` is being used in a function's parameters.
     /// ### Why is this bad?
     /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index 57e6caa8711..012aa5a1d1d 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
             if expr1.span.ctxt() == ctxt;
             if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
             if BinOpKind::Add == op1.node;
-            if let ExprKind::Lit(ref lit) = value.kind;
+            if let ExprKind::Lit(lit) = value.kind;
             if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
             if block.expr.is_none();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 0c7aea6da8f..1e99b6faa6c 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                 // Get the variable name
                 let var_name = ares_path.segments[0].ident.name.as_str();
                 match cond_num_val.kind {
-                    ExprKind::Lit(ref cond_lit) => {
+                    ExprKind::Lit(cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
                             if cx.typeck_results().expr_ty(cond_left).is_signed() {
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index c384172fbde..924a361c0f6 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
+                    if constant(cx, cx.typeck_results(), index).is_some() {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 52d716feea0..b992d689aa9 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
                 span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
             }};
 
-            if matches!(item.kind, ItemKind::Mod(_)) {
-                for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
-                    if_chain! {
-                        if attr.has_name(sym::cfg);
+            if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
+			// Check that it works the same way, the only I way I've found for #10713
+				for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
+					if_chain! {
+						if attr.has_name(sym::cfg);
                         if let Some(mitems) = attr.meta_item_list();
                         if let [mitem] = &*mitems;
                         if mitem.has_name(sym::test);
                         then {
-                            was_test_mod_visited = true;
+							was_test_mod_visited = true;
                             test_mod_span = Some(item.span);
                         }
                     }
                 }
-            }
+			}
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 1b054481371..0ca31033b16 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// It checks for the size of a `Future` created by `async fn` or `async {}`.
     ///
     /// ### Why is this bad?
-    /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
+    /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
     /// large size of a `Future` may cause stack overflows.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index fec9c6f626c..17bd89efaee 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -532,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
 }
 
 fn is_empty_string(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(lit, _) = lit.node {
             let lit = lit.as_str();
             return lit.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 637b7de920e..16772a9d598 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    None,
-                    "consider adding a type annotation or removing the `let` keyword",
+                    Some(
+						Span::new(local.pat.span.hi(),
+						local.pat.span.hi() + BytePos(1),
+						local.pat.span.ctxt(),
+						local.pat.span.parent()
+					)),
+                    "consider adding a type annotation",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9e65f9ecd16..3517842a01e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -94,6 +94,7 @@ mod crate_in_macro_def;
 mod create_dir;
 mod dbg_macro;
 mod default;
+mod default_constructed_unit_structs;
 mod default_instead_of_iter_empty;
 mod default_numeric_fallback;
 mod default_union_representation;
@@ -933,7 +934,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
+    let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
+    store.register_late_pass(move |_| {
+        Box::new(semicolon_block::SemicolonBlock::new(
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        ))
+    });
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
@@ -963,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
+    store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index c87fc4f90e2..d4c3f76b864 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -15,7 +15,7 @@ use rustc_span::symbol::sym;
 use std::fmt::Display;
 use std::iter::Iterator;
 
-/// Checks for for loops that sequentially copy items from one slice-like
+/// Checks for `for` loops that sequentially copy items from one slice-like
 /// object to another.
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
new file mode 100644
index 00000000000..cb9c84be4c7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -0,0 +1,110 @@
+use clippy_utils::{
+    diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
+    match_def_path, paths,
+    source::snippet,
+    SpanlessEq,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::borrow::Cow;
+
+use super::MANUAL_WHILE_LET_SOME;
+
+/// The kind of statement that the `pop()` call appeared in.
+///
+/// Depending on whether the value was assigned to a variable or not changes what pattern
+/// we use for the suggestion.
+#[derive(Copy, Clone)]
+enum PopStmt<'hir> {
+    /// `x.pop().unwrap()` was and assigned to a variable.
+    /// The pattern of this local variable will be used and the local statement
+    /// is deleted in the suggestion.
+    Local(&'hir Pat<'hir>),
+    /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable.
+    /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression
+    /// is replaced with that identifier.
+    Anonymous,
+}
+
+fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) {
+    span_lint_and_then(
+        cx,
+        MANUAL_WHILE_LET_SOME,
+        pop_span,
+        "you seem to be trying to pop elements from a `Vec` in a loop",
+        |diag| {
+            let (pat, pop_replacement) = match pop_stmt_kind {
+                PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()),
+                PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()),
+            };
+
+            let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
+            multispan_sugg_with_applicability(
+                diag,
+                "consider using a `while..let` loop",
+                Applicability::MachineApplicable,
+                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
+            );
+        },
+    );
+}
+
+fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
+    if let ExprKind::MethodCall(..) = expr.kind
+        && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    {
+        match_def_path(cx, id, method)
+    } else {
+        false
+    }
+}
+
+fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
+    if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
+        && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
+        && match_method_call(cx, unwrap_recv, &paths::VEC_POP)
+        && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
+    {
+        // make sure they're the same `Vec`
+        SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv)
+    } else {
+        false
+    }
+}
+
+fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Local(local) = stmt.kind
+        && let Some(init) = local.init
+        && is_vec_pop_unwrap(cx, init, is_empty_recv)
+    {
+        report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span);
+    }
+}
+
+fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
+        if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
+            let offending_arg = args
+                .iter()
+                .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
+
+            if let Some(offending_arg) = offending_arg {
+                report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
+            }
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
+    if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
+        && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
+        && match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
+        && let ExprKind::Block(body, _) = body.kind
+        && let Some(stmt) = body.stmts.first()
+    {
+        check_local(cx, stmt, is_empty_recv, loop_span);
+        check_call_arguments(cx, stmt, is_empty_recv, loop_span);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 610a0233eee..f83ad388a74 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -7,6 +7,7 @@ mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
+mod manual_while_let_some;
 mod missing_spin_loop;
 mod mut_range_bound;
 mod needless_range_loop;
@@ -575,6 +576,36 @@ declare_clippy_lint! {
     "manual implementation of `Iterator::find`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
+    /// in the body as a separate operation.
+    ///
+    /// ### Why is this bad?
+    /// Such loops can be written in a more idiomatic way by using a while-let loop and directly
+    /// pattern matching on the return value of `Vec::pop()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while !numbers.is_empty() {
+    ///     let number = numbers.pop().unwrap();
+    ///     // use `number`
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while let Some(number) = numbers.pop() {
+    ///     // use `number`
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MANUAL_WHILE_LET_SOME,
+    style,
+    "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
+}
+
 declare_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
@@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
     MANUAL_FIND,
+    MANUAL_WHILE_LET_SOME
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
+        if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
             missing_spin_loop::check(cx, condition, body);
+            manual_while_let_some::check(cx, condition, body, span);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 5c317c2a5bb..cb446567506 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>(
     indexed_ty: Ty<'tcx>,
 ) -> bool {
     if_chain! {
-        if let ExprKind::Lit(ref lit) = end.kind;
+        if let ExprKind::Lit(lit) = end.kind;
         if let ast::LitKind::Int(end_int, _) = lit.node;
         if let ty::Array(_, arr_len_const) = indexed_ty.kind();
         if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index ce5d657bcf0..45ea5aab4c2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             };
             let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
             let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
-            // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+            // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
             span_lint_and_then(
                 cx,
                 MANUAL_ASSERT,
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 98e698c6c2a..1247370b74a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                 if source != MatchSource::Normal {
                     return;
                 }
-                // Any other number than two arms doesn't (neccessarily)
+                // Any other number than two arms doesn't (necessarily)
                 // have a trivial mapping to let else.
                 if arms.len() != 2 {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 72cdb9c1736..5259066eb71 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.64.0"]
     pub MANUAL_RETAIN,
     perf,
-    "`retain()` is simpler and the same functionalitys"
+    "`retain()` is simpler and the same functionalities"
 }
 
 pub struct ManualRetain {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
index df1e585f10b..69105ff0d5c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
                 if arms.len() == 2 {
                     // no guards
                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
+                        if let ExprKind::Lit(lit) = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
                                 LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 7b609ff3df8..af121f317cd 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>(
     // Determine which function should be used, and the type contained by the corresponding
     // variant.
     let (good_method, inner_ty) = match check_pat.kind {
-        PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
-            if let PatKind::Wild = sub_pat.kind {
+        PatKind::TupleStruct(ref qpath, args, rest) => {
+            let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
+            let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
+
+            if is_wildcard || is_rest {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
                 let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
@@ -334,7 +337,7 @@ fn find_good_method_for_match<'a>(
     };
 
     match body_node_pair {
-        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+        (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
             (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
             (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
             _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 27a05337a29..8984b2cf8fd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -18,7 +18,7 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Lit(ref lit) = info.other.kind;
+        if let hir::ExprKind::Lit(lit) = info.other.kind;
         if let ast::LitKind::Char(c) = lit.node;
         then {
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index 83c1bf20346..e2029da8081 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::Range::hir(index_expr);
-            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
+            if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 23d23f25f14..bd625a6914c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -42,11 +42,11 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         // 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.is_empty() {
             let argument_option = match arguments[0].kind {
-                ExprKind::Lit(ref span) => {
+                ExprKind::Lit(span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
                         ..
-                    } = *span
+                    } = span
                     {
                         if *lit { Argument::True } else { Argument::False }
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index e3f2de3cd46..0284d9dea30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
-        if let ExprKind::Lit(ref lit) = arg.kind;
+        if let ExprKind::Lit(lit) = arg.kind;
         if let LitKind::Str(ref path_lit, _) = lit.node;
         if let pushed_path = Path::new(path_lit.as_str());
         if let Some(pushed_path_lit) = pushed_path.to_str();
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index 361a3082f94..c028e954381 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
         // check if argument of `SeekFrom::Current` is `0`
         if args.len() == 1 &&
-            let ExprKind::Lit(ref lit) = args[0].kind &&
+            let ExprKind::Lit(lit) = args[0].kind &&
             let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
             return true
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 660b7049cce..787e9e0ebd2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
         match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
         args1.len() == 1 &&
-        let ExprKind::Lit(ref lit) = args1[0].kind &&
+        let ExprKind::Lit(lit) = args1[0].kind &&
         let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
     {
         let method_call_span = expr.span.with_lo(name_span.lo());
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index aa87dead38f..5a3d12fd790 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -78,7 +78,7 @@ pub(super) fn check(
     }
 
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = init.kind {
+    if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index e99081ad062..1adecd2caac 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
     /// Checks if a provided method is used implicitly by a trait
     /// implementation. A usage example would be a wrapper where every method
     /// should perform some operation before delegating to the inner type's
-    /// implemenation.
+    /// implementation.
     ///
     /// This lint should typically be enabled on a specific trait `impl` item
     /// rather than globally.
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index c87059bf61d..71281a0b40b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,10 +3,12 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
+use clippy_utils::{
+    get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+};
+use clippy_utils::{higher, SpanlessEq};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
@@ -77,7 +79,39 @@ declare_clippy_lint! {
     "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 }
 
-declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions of the form `if c { x = true } else { x = false }`
+    /// (or vice versa) and suggest assigning the variable directly from the
+    /// condition.
+    ///
+    /// ### Why is this bad?
+    /// Redundant code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// if must_keep(x, y) {
+    ///     skip = false;
+    /// } else {
+    ///     skip = true;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// skip = !must_keep(x, y);
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub NEEDLESS_BOOL_ASSIGN,
+    complexity,
+    "setting the same boolean variable in both branches of an if-statement"
+}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]);
 
 fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     let mut inner = e;
@@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     _ => (),
                 }
             }
+            if let Some((lhs_a, a)) = fetch_assign(then) &&
+                let Some((lhs_b, b)) = fetch_assign(r#else) &&
+                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
+                span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
+            {
+                let mut applicability = Applicability::MachineApplicable;
+                let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
+                let sugg = if a == b {
+                    format!("{cond}; {lhs} = {a:?};")
+                } else {
+                    format!("{lhs} = {};", if a { cond } else { !cond })
+                };
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_BOOL_ASSIGN,
+                    e.span,
+                    "this if-then-else expression assigns a bool literal",
+                    "you can reduce it to",
+                    sugg,
+                    applicability
+                );
+            }
         }
     }
 }
@@ -369,10 +426,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
 }
 
 fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
-    if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+    if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
         if let LitKind::Bool(value) = lit_ptr.node {
             return Some(value);
         }
     }
     None
 }
+
+fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> {
+    if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind {
+        fetch_bool_expr(rhs).map(|b| (lhs, b))
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 6e54b243c03..da1b9d99931 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -49,14 +49,14 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
 
 fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
     if is_start &&
-    let ExprKind::Lit(ref literal) = e.kind &&
+    let ExprKind::Lit(literal) = e.kind &&
     let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
     {
         // don't check floating point literals on the start expression of a range
         return;
     }
     if_chain! {
-        if let ExprKind::Lit(ref literal) = e.kind;
+        if let ExprKind::Lit(literal) = e.kind;
         // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
         if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
         // inspect the source code of the expression for parenthesis
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index ed3e2c6e7f4..db0e22842d1 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Lit(ref l) = lit.kind;
+        if let ExprKind::Lit(l) = lit.kind;
         if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
         if cx.typeck_results().expr_ty(exp).is_integral();
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index fafcf257094..f72595987ee 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -110,7 +110,7 @@ impl ArithmeticSideEffects {
     /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
     fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
         let actual = peel_hir_expr_unary(expr).0;
-        if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
+        if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             return Some(n)
         }
         if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 9e6c6c73d4f..b8b32df6cc6 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -180,7 +180,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
         .allow_invalid_utf8(!utf8)
         .build();
 
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
             let r = r.as_str();
             let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 34a3e5ddf4f..419d7991f0e 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
     restriction,
     "add a semicolon outside the block"
 }
-declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+#[derive(Copy, Clone)]
+pub struct SemicolonBlock {
+    semicolon_inside_block_ignore_singleline: bool,
+    semicolon_outside_block_ignore_multiline: bool,
+}
+
+impl SemicolonBlock {
+    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+        Self {
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        }
+    }
+
+    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+        let insert_span = tail.span.source_callsite().shrink_to_hi();
+        let remove_span = semi_span.with_lo(block.span.hi());
+
+        if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_INSIDE_BLOCK,
+            semi_span,
+            "consider moving the `;` inside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+
+    fn semicolon_outside_block(
+        self,
+        cx: &LateContext<'_>,
+        block: &Block<'_>,
+        tail_stmt_expr: &Expr<'_>,
+        semi_span: Span,
+    ) {
+        let insert_span = block.span.with_lo(block.span.hi());
+        // account for macro calls
+        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_OUTSIDE_BLOCK,
+            block.span,
+            "consider moving the `;` outside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+}
 
 impl LateLintPass<'_> for SemicolonBlock {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
                     span,
                     ..
                 } = stmt else { return };
-                semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr, span);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
                 ..
-            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            }) if !block.span.from_expansion() => {
+                self.semicolon_inside_block(cx, block, tail, stmt.span);
+            },
             _ => (),
         }
     }
 }
 
-fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
-    let insert_span = tail.span.source_callsite().shrink_to_hi();
-    let remove_span = semi_span.with_lo(block.span.hi());
-
-    span_lint_and_then(
-        cx,
-        SEMICOLON_INSIDE_BLOCK,
-        semi_span,
-        "consider moving the `;` inside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
-}
-
-fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
-    let insert_span = block.span.with_lo(block.span.hi());
-    // account for macro calls
-    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
+    if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
+        return Some(line.line);
+    }
 
-    span_lint_and_then(
-        cx,
-        SEMICOLON_OUTSIDE_BLOCK,
-        block.span,
-        "consider moving the `;` outside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
+    None
 }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index ae7d19624ba..993f9373d85 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
-        if pat.span.desugaring_kind().is_some() {
+        if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index a2109038a05..858135c8d46 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -74,7 +74,7 @@ enum InitializationType<'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
+        // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index b2f4b310915..5b588e914fd 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
+            if !in_external_macro(cx.sess(), e.span);
             if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
             if let ExprKind::Lit(lit) = &receiver.kind;
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 98f5b47f7a0..bb9da3a2047 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
         if let Some(last_field) = data.fields().last();
         if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
-        // Then check if that that array zero-sized
+        // Then check if that array is zero-sized
         let length = Const::from_anon_const(cx.tcx, length.def_id);
         let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
         if let Some(length) = length;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c6834a8fdaa..3c873a5901d 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -90,8 +90,8 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// `Option<_>` represents an optional value. `Option<Option<_>>`
-    /// represents an optional optional value which is logically the same thing as an optional
-    /// value but has an unneeded extra level of wrapping.
+    /// represents an optional value which itself wraps an optional. This is logically the
+    /// same thing as an optional value but has an unneeded extra level of wrapping.
     ///
     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
     /// consider a custom `enum` instead, with clear names for each case.
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index 8980283e5c8..e275bfd37b0 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let ExprKind::Lit(ref lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind {
             if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
                 check_str(cx, lit.span, expr.hir_id);
             }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index af1c8d83b4f..e7449639f3a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -109,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         // Ignore implementations of traits, because the lint should be on the
-        // trait, not on the implmentation of it.
+        // trait, not on the implementation of it.
         let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
         let ItemKind::Impl(parent) = parent.kind else { return };
         if parent.of_trait.is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 01927b6b5f1..108077b9d15 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -333,7 +333,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     #[allow(clippy::too_many_lines)]
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
+        if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
             chain!(
                 self,
@@ -561,7 +561,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::OffsetOf(container, ref fields) => {
                 bind!(self, container, fields);
                 kind!("OffsetOf({container}, {fields})");
-            }
+            },
             ExprKind::Struct(qpath, fields, base) => {
                 bind!(self, qpath, fields);
                 opt_bind!(self, base);
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 67bb499c455..5f05d971fce 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -277,6 +277,14 @@ define_Conf! {
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
     (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Lint: SEMICOLON_INSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's multiline.
+    (semicolon_inside_block_ignore_singleline: bool = false),
+    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's singleline.
+    (semicolon_outside_block_ignore_multiline: bool = false),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value