about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/allow_attributes.rs71
-rw-r--r--clippy_lints/src/booleans.rs25
-rw-r--r--clippy_lints/src/copies.rs70
-rw-r--r--clippy_lints/src/declared_lints.rs3
-rw-r--r--clippy_lints/src/default.rs9
-rw-r--r--clippy_lints/src/derive.rs8
-rw-r--r--clippy_lints/src/functions/must_use.rs5
-rw-r--r--clippy_lints/src/if_then_some_else_none.rs17
-rw-r--r--clippy_lints/src/let_with_type_underscore.rs2
-rw-r--r--clippy_lints/src/lib.rs9
-rw-r--r--clippy_lints/src/loops/same_item_push.rs32
-rw-r--r--clippy_lints/src/manual_async_fn.rs15
-rw-r--r--clippy_lints/src/manual_clamp.rs7
-rw-r--r--clippy_lints/src/manual_main_separator_str.rs74
-rw-r--r--clippy_lints/src/matches/manual_unwrap_or.rs12
-rw-r--r--clippy_lints/src/matches/match_bool.rs20
-rw-r--r--clippy_lints/src/matches/match_ref_pats.rs28
-rw-r--r--clippy_lints/src/matches/match_single_binding.rs52
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs17
-rw-r--r--clippy_lints/src/matches/single_match.rs18
-rw-r--r--clippy_lints/src/methods/bind_instead_of_map.rs11
-rw-r--r--clippy_lints/src/methods/clone_on_ref_ptr.rs8
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs28
-rw-r--r--clippy_lints/src/misc.rs17
-rw-r--r--clippy_lints/src/mut_key.rs60
-rw-r--r--clippy_lints/src/needless_bool.rs13
-rw-r--r--clippy_lints/src/no_mangle_with_rust_abi.rs28
-rw-r--r--clippy_lints/src/option_if_let_else.rs28
-rw-r--r--clippy_lints/src/redundant_async_block.rs39
-rw-r--r--clippy_lints/src/semicolon_if_nothing_returned.rs13
-rw-r--r--clippy_lints/src/significant_drop_tightening.rs38
-rw-r--r--clippy_lints/src/swap.rs7
-rw-r--r--clippy_lints/src/unit_types/let_unit_value.rs7
-rw-r--r--clippy_lints/src/unnecessary_struct_initialization.rs84
-rw-r--r--clippy_lints/src/useless_conversion.rs14
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/wildcard_imports.rs8
37 files changed, 623 insertions, 276 deletions
diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs
new file mode 100644
index 00000000000..15d46e954a9
--- /dev/null
+++ b/clippy_lints/src/allow_attributes.rs
@@ -0,0 +1,71 @@
+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_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// Detects uses of the `#[allow]` attribute and suggests replacing it with
+    /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
+    ///
+    /// The expect attribute is still unstable and requires the `lint_reasons`
+    /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to
+    /// the crate root.
+    ///
+    /// This lint only warns outer attributes (`#[allow]`), as inner attributes
+    /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `#[expect]` attributes suppress the lint emission, but emit a warning, if
+    /// the expectation is unfulfilled. This can be useful to be notified when the
+    /// lint is no longer triggered.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[allow(unused_mut)]
+    /// fn foo() -> usize {
+    ///    let mut a = Vec::new();
+    ///    a.len()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #![feature(lint_reasons)]
+    /// #[expect(unused_mut)]
+    /// fn foo() -> usize {
+    ///     let mut a = Vec::new();
+    ///     a.len()
+    /// }
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub ALLOW_ATTRIBUTES,
+    restriction,
+    "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
+}
+
+declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]);
+
+impl LateLintPass<'_> for AllowAttribute {
+    // Separate each crate's features.
+    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
+        if_chain! {
+            if cx.tcx.features().lint_reasons;
+            if let AttrStyle::Outer = attr.style;
+            if let Some(ident) = attr.ident();
+            if ident.name == rustc_span::symbol::sym::allow;
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    ALLOW_ATTRIBUTES,
+                    ident.span,
+                    "#[allow] attribute found",
+                    "replace it with",
+                    "expect".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index e8106beec37..29fde9336c0 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind {
-            if let Some(suggestion) = simplify_not(self.cx, inner) {
-                span_lint_and_sugg(
-                    self.cx,
-                    NONMINIMAL_BOOL,
-                    expr.span,
-                    "this boolean expression can be simplified",
-                    "try",
-                    suggestion,
-                    Applicability::MachineApplicable,
-                );
-            }
+        if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind &&
+            !inner.span.from_expansion() &&
+            let Some(suggestion) = simplify_not(self.cx, inner)
+        {
+            span_lint_and_sugg(
+                self.cx,
+                NONMINIMAL_BOOL,
+                expr.span,
+                "this boolean expression can be simplified",
+                "try",
+                suggestion,
+                Applicability::MachineApplicable,
+            );
         }
 
         walk_expr(self, expr);
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index f10c35cde52..970f5004993 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -1,18 +1,20 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
-use clippy_utils::ty::needs_ordered_drop;
+use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop};
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
-    capture_local_usage, eq_expr_value, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause,
-    is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
+    capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt,
+    if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq,
 };
 use core::iter;
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::intravisit;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_middle::query::Key;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::walk_chain;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Span, Symbol};
@@ -159,7 +161,21 @@ declare_clippy_lint! {
     "`if` statement with shared code in all blocks"
 }
 
-declare_lint_pass!(CopyAndPaste => [
+pub struct CopyAndPaste {
+    ignore_interior_mutability: Vec<String>,
+    ignored_ty_ids: DefIdSet,
+}
+
+impl CopyAndPaste {
+    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+        Self {
+            ignore_interior_mutability,
+            ignored_ty_ids: DefIdSet::new(),
+        }
+    }
+}
+
+impl_lint_pass!(CopyAndPaste => [
     IFS_SAME_COND,
     SAME_FUNCTIONS_IN_IF_CONDITION,
     IF_SAME_THEN_ELSE,
@@ -167,10 +183,18 @@ declare_lint_pass!(CopyAndPaste => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        for ignored_ty in &self.ignore_interior_mutability {
+            let path: Vec<&str> = ignored_ty.split("::").collect();
+            for id in def_path_def_ids(cx, path.as_slice()) {
+                self.ignored_ty_ids.insert(id);
+            }
+        }
+    }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) {
             let (conds, blocks) = if_sequence(expr);
-            lint_same_cond(cx, &conds);
+            lint_same_cond(cx, &conds, &self.ignored_ty_ids);
             lint_same_fns_in_if_cond(cx, &conds);
             let all_same =
                 !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks);
@@ -547,9 +571,39 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
     })
 }
 
+fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool {
+    let caller_ty = cx.typeck_results().expr_ty(caller_expr);
+    // Check if given type has inner mutability and was not set to ignored by the configuration
+    let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty)
+        && !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id));
+
+    is_inner_mut_ty
+        || caller_ty.is_mutable_ptr()
+        // `find_binding_init` will return the binding iff its not mutable
+        || path_to_local(caller_expr)
+            .and_then(|hid| find_binding_init(cx, hid))
+            .is_none()
+}
+
 /// Implementation of `IFS_SAME_COND`.
-fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
-    for (i, j) in search_same(conds, |e| hash_expr(cx, e), |lhs, rhs| eq_expr_value(cx, lhs, rhs)) {
+fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) {
+    for (i, j) in search_same(
+        conds,
+        |e| hash_expr(cx, e),
+        |lhs, rhs| {
+            // Ignore eq_expr side effects iff one of the expressin 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) {
+                    false
+                } else {
+                    SpanlessEq::new(cx).eq_expr(lhs, rhs)
+                }
+            } else {
+                eq_expr_value(cx, lhs, rhs)
+            }
+        },
+    ) {
         span_lint_and_note(
             cx,
             IFS_SAME_COND,
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index cc6024b87cd..8ca91301472 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -35,6 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+    crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
     crate::as_conversions::AS_CONVERSIONS_INFO,
@@ -262,6 +263,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_clamp::MANUAL_CLAMP_INFO,
     crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
     crate::manual_let_else::MANUAL_LET_ELSE_INFO,
+    crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
     crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
@@ -616,6 +618,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
     crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
     crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
+    crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,
     crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
     crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
     crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index 080d44e6398..80c22742ba4 100644
--- a/clippy_lints/src/default.rs
+++ b/clippy_lints/src/default.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
-use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_drop, is_copy};
 use clippy_utils::{
     any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
@@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 }
             };
 
+            let init_ctxt = local.span.ctxt();
+
             // find all "later statement"'s where the fields of the binding set as
             // Default::default() get reassigned, unless the reassignment refers to the original binding
             let mut first_assign = None;
@@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 // find out if and which field was set by this `consecutive_statement`
                 if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
                     // interrupt and cancel lint if assign_rhs references the original binding
-                    if contains_name(binding_name, assign_rhs, cx) {
+                    if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() {
                         cancel_lint = true;
                         break;
                     }
@@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                     .iter()
                     .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
 
+                let mut app = Applicability::Unspecified;
                 let field_list = assigned_fields
                     .into_iter()
                     .map(|(field, rhs)| {
                         // extract and store the assigned value for help message
-                        let value_snippet = snippet_with_macro_callsite(cx, rhs.span, "..");
+                        let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0;
                         format!("{field}: {value_snippet}")
                     })
                     .collect::<Vec<String>>()
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index 715348e869e..f425dd5fb70 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -24,8 +24,8 @@ use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for deriving `Hash` but implementing `PartialEq`
-    /// explicitly or vice versa.
+    /// Lints against manual `PartialEq` implementations for types with a derived `Hash`
+    /// implementation.
     ///
     /// ### Why is this bad?
     /// The implementation of these traits must agree (for
@@ -54,8 +54,8 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for deriving `Ord` but implementing `PartialOrd`
-    /// explicitly or vice versa.
+    /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord`
+    /// or `PartialOrd` implementation.
     ///
     /// ### Why is this bad?
     /// The implementation of these traits must agree (for
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index 67877780c0e..1e9e826631c 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -50,10 +50,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
-        } else if is_public
-            && !is_proc_macro(attrs)
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
-        {
+        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index 9cadaaa493e..725bd3d54bc 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
+use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             return;
         }
 
+        let ctxt = expr.span.ctxt();
+
         if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
             && let ExprKind::Block(then_block, _) = then.kind
             && let Some(then_expr) = then_block.expr
             && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
+            && then_expr.span.ctxt() == ctxt
             && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
             && !stmts_contains_early_return(then_block.stmts)
         {
-            let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
-            let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
-                format!("({cond_snip})")
-            } else {
-                cond_snip.into_owned()
-            };
-            let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
+            let mut app = Applicability::Unspecified;
+            let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string();
+            let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
             let mut method_body = if then_block.stmts.is_empty() {
                 arg_snip.into_owned()
             } else {
diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs
index ba51973f2f9..c01e3882d52 100644
--- a/clippy_lints/src/let_with_type_underscore.rs
+++ b/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::*;
+use rustc_hir::{Local, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 491732be208..c9210bf73f8 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -67,6 +67,7 @@ mod declared_lints;
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
 mod as_conversions;
@@ -179,6 +180,7 @@ mod manual_bits;
 mod manual_clamp;
 mod manual_is_ascii_check;
 mod manual_let_else;
+mod manual_main_separator_str;
 mod manual_non_exhaustive;
 mod manual_rem_euclid;
 mod manual_retain;
@@ -300,6 +302,7 @@ mod unit_types;
 mod unnamed_address;
 mod unnecessary_owned_empty_strings;
 mod unnecessary_self_imports;
+mod unnecessary_struct_initialization;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
 mod unsafe_removed_from_name;
@@ -656,7 +659,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
     store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
     store.register_late_pass(|_| Box::new(regex::Regex));
-    store.register_late_pass(|_| Box::new(copies::CopyAndPaste));
+    let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
+    store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
     store.register_late_pass(|_| Box::new(format::UselessFormat));
     store.register_late_pass(|_| Box::new(swap::Swap));
@@ -933,6 +937,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
     store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock));
     store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
+    store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
+    store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
+    store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index 540656a2cd9..9d9341559ac 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -1,15 +1,17 @@
 use super::SAME_ITEM_PUSH;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::path_to_local;
-use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
+use rustc_span::SyntaxContext;
 use std::iter::Iterator;
 
 /// Detects for loop pushing the same item into a Vec
@@ -20,9 +22,10 @@ pub(super) fn check<'tcx>(
     body: &'tcx Expr<'_>,
     _: &'tcx Expr<'_>,
 ) {
-    fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
-        let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
-        let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
+    fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) {
+        let mut app = Applicability::Unspecified;
+        let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0;
+        let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0;
 
         span_lint_and_help(
             cx,
@@ -43,7 +46,7 @@ pub(super) fn check<'tcx>(
     walk_expr(&mut same_item_push_visitor, body);
     if_chain! {
         if same_item_push_visitor.should_lint();
-        if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push;
+        if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push;
         let vec_ty = cx.typeck_results().expr_ty(vec);
         let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
         if cx
@@ -69,11 +72,11 @@ pub(super) fn check<'tcx>(
                                 then {
                                     match init.kind {
                                         // immutable bindings that are initialized with literal
-                                        ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                                        ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
                                         // immutable bindings that are initialized with constant
                                         ExprKind::Path(ref path) => {
                                             if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
-                                                emit_lint(cx, vec, pushed_item);
+                                                emit_lint(cx, vec, pushed_item, ctxt);
                                             }
                                         }
                                         _ => {},
@@ -82,11 +85,11 @@ pub(super) fn check<'tcx>(
                             }
                         },
                         // constant
-                        Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
+                        Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt),
                         _ => {},
                     }
                 },
-                ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
                 _ => {},
             }
         }
@@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> {
     non_deterministic_expr: bool,
     multiple_pushes: bool,
     // this field holds the last vec push operation visited, which should be the only push seen
-    vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>,
+    vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>,
     cx: &'a LateContext<'tcx>,
     used_locals: FxHashSet<HirId>,
 }
@@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
         if_chain! {
             if !self.non_deterministic_expr;
             if !self.multiple_pushes;
-            if let Some((vec, _)) = self.vec_push;
+            if let Some((vec, _, _)) = self.vec_push;
             if let Some(hir_id) = path_to_local(vec);
             then {
                 !self.used_locals.contains(&hir_id)
@@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
 
 // Given some statement, determine if that statement is a push on a Vec. If it is, return
 // the Vec being pushed into and the item being pushed
-fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+fn get_vec_push<'tcx>(
+    cx: &LateContext<'tcx>,
+    stmt: &'tcx Stmt<'_>,
+) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> {
     if_chain! {
             // Extract method being called
             if let StmtKind::Semi(semi_stmt) = &stmt.kind;
@@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
             if path.ident.name.as_str() == "push";
             then {
-                return Some((self_expr, pushed_item))
+                return Some((self_expr, pushed_item, semi_stmt.span.ctxt()))
             }
     }
     None
diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs
index f97c6bcb5d1..577bc1d661d 100644
--- a/clippy_lints/src/manual_async_fn.rs
+++ b/clippy_lints/src/manual_async_fn.rs
@@ -5,7 +5,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
-    ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
+    ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        _: LocalDefId,
+        def_id: LocalDefId,
     ) {
         if_chain! {
             if let Some(header) = kind.header();
@@ -59,6 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
             if let ExprKind::Block(block, _) = body.value.kind;
             if block.stmts.is_empty();
             if let Some(closure_body) = desugared_async_block(cx, block);
+            if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
+                cx.tcx.hir().get_by_def_id(def_id);
             then {
                 let header_span = span.with_hi(ret_ty.span.hi());
 
@@ -69,15 +71,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
                     "this function can be simplified using the `async fn` syntax",
                     |diag| {
                         if_chain! {
+                            if let Some(vis_snip) = snippet_opt(cx, *vis_span);
                             if let Some(header_snip) = snippet_opt(cx, header_span);
                             if let Some(ret_pos) = position_before_rarrow(&header_snip);
                             if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
                             then {
+                                let header_snip = if vis_snip.is_empty() {
+                                    format!("async {}", &header_snip[..ret_pos])
+                                } else {
+                                    format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos])
+                                };
+
                                 let help = format!("make the function `async` and {ret_sugg}");
                                 diag.span_suggestion(
                                     header_span,
                                     help,
-                                    format!("async {}{ret_snip}", &header_snip[..ret_pos]),
+                                    format!("{header_snip}{ret_snip}"),
                                     Applicability::MachineApplicable
                                 );
 
diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs
index f239736d38a..440362b96b4 100644
--- a/clippy_lints/src/manual_clamp.rs
+++ b/clippy_lints/src/manual_clamp.rs
@@ -6,7 +6,8 @@ use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::is_const_evaluatable;
 use clippy_utils::MaybePath;
 use clippy_utils::{
-    eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+    eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks,
+    peel_blocks_with_stmt,
 };
 use itertools::Itertools;
 use rustc_errors::Applicability;
@@ -117,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
         if !self.msrv.meets(msrvs::CLAMP) {
             return;
         }
-        if !expr.span.from_expansion() {
+        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
             let suggestion = is_if_elseif_else_pattern(cx, expr)
                 .or_else(|| is_max_min_pattern(cx, expr))
                 .or_else(|| is_call_max_min_pattern(cx, expr))
@@ -130,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
     }
 
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if !self.msrv.meets(msrvs::CLAMP) {
+        if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) {
             return;
         }
         for suggestion in is_two_if_pattern(cx, block) {
diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs
new file mode 100644
index 00000000000..c292bbe4e93
--- /dev/null
+++ b/clippy_lints/src/manual_main_separator_str.rs
@@ -0,0 +1,74 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Expr, ExprKind, Mutability, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used
+    /// to build a `&str`.
+    ///
+    /// ### Why is this bad?
+    /// There exists a `std::path::MAIN_SEPARATOR_STR` which does not require
+    /// an extra memory allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let s: &str = &std::path::MAIN_SEPARATOR.to_string();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let s: &str = std::path::MAIN_SEPARATOR_STR;
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MANUAL_MAIN_SEPARATOR_STR,
+    complexity,
+    "`&std::path::MAIN_SEPARATOR.to_string()` can be replaced by `std::path::MAIN_SEPARATOR_STR`"
+}
+
+pub struct ManualMainSeparatorStr {
+    msrv: Msrv,
+}
+
+impl ManualMainSeparatorStr {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
+
+impl LateLintPass<'_> for ManualMainSeparatorStr {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) &&
+            let (target, _) = peel_hir_expr_refs(expr) &&
+            is_trait_method(cx, target, sym::ToString) &&
+            let ExprKind::MethodCall(path, receiver, &[], _) = target.kind &&
+            path.ident.name == sym::to_string &&
+            let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind &&
+            let Res::Def(DefKind::Const, receiver_def_id) = path.res &&
+            match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) &&
+            let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() &&
+            ty.is_str()
+            {
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_MAIN_SEPARATOR_STR,
+                    expr.span,
+                    "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`",
+                    "replace with",
+                    "std::path::MAIN_SEPARATOR_STR".to_owned(),
+                    Applicability::MachineApplicable,
+                );
+            }
+    }
+
+    extract_msrv_attr!(LateContext);
+}
diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs
index 6447899f2b9..b94501bf0ad 100644
--- a/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -32,14 +32,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
             let reindented_or_body =
                 reindent_multiline(or_body_snippet.into(), true, Some(indent));
 
-            let suggestion = if scrutinee.span.from_expansion() {
-                    // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
-                    sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
-                }
-                else {
-                    sugg::Sugg::hir(cx, scrutinee, "..").maybe_par()
-                };
-
+            let mut app = Applicability::MachineApplicable;
+            let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
             span_lint_and_sugg(
                 cx,
                 MANUAL_UNWRAP_OR, expr.span,
@@ -48,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
                 format!(
                     "{suggestion}.unwrap_or({reindented_or_body})",
                 ),
-                Applicability::MachineApplicable,
+                app,
             );
         }
     }
diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs
index 1c216e13570..df1e585f10b 100644
--- a/clippy_lints/src/matches/match_bool.rs
+++ b/clippy_lints/src/matches/match_bool.rs
@@ -10,9 +10,9 @@ use rustc_middle::ty;
 
 use super::MATCH_BOOL;
 
-pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     // Type of expression is `bool`.
-    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
+    if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
@@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
                     };
 
                     if let Some((true_expr, false_expr)) = exprs {
+                        let mut app = Applicability::HasPlaceholders;
+                        let ctxt = expr.span.ctxt();
                         let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
                             (false, false) => Some(format!(
                                 "if {} {} else {}",
-                                snippet(cx, ex.span, "b"),
-                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
-                                expr_block(cx, false_expr, None, "..", Some(expr.span))
+                                snippet(cx, scrutinee.span, "b"),
+                                expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app),
+                                expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
                             )),
                             (false, true) => Some(format!(
                                 "if {} {}",
-                                snippet(cx, ex.span, "b"),
-                                expr_block(cx, true_expr, None, "..", Some(expr.span))
+                                snippet(cx, scrutinee.span, "b"),
+                                expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app)
                             )),
                             (true, false) => {
-                                let test = Sugg::hir(cx, ex, "..");
+                                let test = Sugg::hir(cx, scrutinee, "..");
                                 Some(format!(
                                     "if {} {}",
                                     !test,
-                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
+                                    expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
                                 ))
                             },
                             (true, true) => None,
diff --git a/clippy_lints/src/matches/match_ref_pats.rs b/clippy_lints/src/matches/match_ref_pats.rs
index 80f964ba1b7..aba4c85c59e 100644
--- a/clippy_lints/src/matches/match_ref_pats.rs
+++ b/clippy_lints/src/matches/match_ref_pats.rs
@@ -1,13 +1,14 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
-use clippy_utils::source::snippet;
+use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use core::iter::once;
+use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
 use rustc_lint::LateContext;
 
 use super::MATCH_REF_PATS;
 
-pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
+pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>)
 where
     'b: 'a,
     I: Clone + Iterator<Item = &'a Pat<'b>>,
@@ -17,13 +18,28 @@ where
     }
 
     let (first_sugg, msg, title);
-    let span = ex.span.source_callsite();
-    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
-        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
+    let ctxt = expr.span.ctxt();
+    let mut app = Applicability::Unspecified;
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind {
+        if scrutinee.span.ctxt() != ctxt {
+            return;
+        }
+        first_sugg = once((
+            scrutinee.span,
+            Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(),
+        ));
         msg = "try";
         title = "you don't need to add `&` to both the expression and the patterns";
     } else {
-        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
+        let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else {
+            return;
+        };
+        first_sugg = once((
+            span,
+            Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app)
+                .deref()
+                .to_string(),
+        ));
         msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
         title = "you don't need to add `&` to all patterns";
     }
diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs
index 065a5c72621..89da7a55cbd 100644
--- a/clippy_lints/src/matches/match_single_binding.rs
+++ b/clippy_lints/src/matches/match_single_binding.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::HirNode;
-use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability};
-use clippy_utils::sugg::Sugg;
+use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability};
 use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -24,21 +23,30 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     let matched_vars = ex.span;
     let bind_names = arms[0].pat.span;
     let match_body = peel_blocks(arms[0].body);
-    let mut snippet_body = if match_body.span.from_expansion() {
-        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
-    } else {
-        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
-    };
+    let mut app = Applicability::MaybeIncorrect;
+    let mut snippet_body = snippet_block_with_context(
+        cx,
+        match_body.span,
+        arms[0].span.ctxt(),
+        "..",
+        Some(expr.span),
+        &mut app,
+    )
+    .0
+    .to_string();
 
     // Do we need to add ';' to suggestion ?
-    if let ExprKind::Block(block, _) = match_body.kind {
-        // macro + expr_ty(body) == ()
-        if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
-            snippet_body.push(';');
+    if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id)
+        && let StmtKind::Expr(_) = stmt.kind
+        && match match_body.kind {
+            // We don't need to add a ; to blocks, unless that block is from a macro expansion
+            ExprKind::Block(block, _) => block.span.from_expansion(),
+            _ => true,
         }
+    {
+        snippet_body.push(';');
     }
 
-    let mut applicability = Applicability::MaybeIncorrect;
     match arms[0].pat.kind {
         PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
             let (target_span, sugg) = match opt_parent_assign_span(cx, ex) {
@@ -48,7 +56,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                         (ex, expr),
                         (bind_names, matched_vars),
                         &snippet_body,
-                        &mut applicability,
+                        &mut app,
                         Some(span),
                         true,
                     );
@@ -60,7 +68,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                         "this assignment could be simplified",
                         "consider removing the `match` expression",
                         sugg,
-                        applicability,
+                        app,
                     );
 
                     return;
@@ -69,10 +77,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                     span,
                     format!(
                         "let {} = {};\n{}let {} = {snippet_body};",
-                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
-                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
+                        snippet_with_applicability(cx, bind_names, "..", &mut app),
+                        snippet_with_applicability(cx, matched_vars, "..", &mut app),
                         " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
-                        snippet_with_applicability(cx, pat_span, "..", &mut applicability)
+                        snippet_with_applicability(cx, pat_span, "..", &mut app)
                     ),
                 ),
                 None => {
@@ -81,7 +89,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                         (ex, expr),
                         (bind_names, matched_vars),
                         &snippet_body,
-                        &mut applicability,
+                        &mut app,
                         None,
                         true,
                     );
@@ -96,7 +104,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                 "this match could be written as a `let` statement",
                 "consider using a `let` statement",
                 sugg,
-                applicability,
+                app,
             );
         },
         PatKind::Wild => {
@@ -106,7 +114,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                     (ex, expr),
                     (bind_names, matched_vars),
                     &snippet_body,
-                    &mut applicability,
+                    &mut app,
                     None,
                     false,
                 );
@@ -118,7 +126,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                     "this match could be replaced by its scrutinee and body",
                     "consider using the scrutinee and body instead",
                     sugg,
-                    applicability,
+                    app,
                 );
             } else {
                 span_lint_and_sugg(
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index df0ea7f5b86..7b609ff3df8 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,6 +1,6 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet;
+use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::any_temporaries_need_ordered_drop;
@@ -150,22 +150,25 @@ fn find_sugg_for_if_let<'tcx>(
             // if/while let ... = ... { ... }
             // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
             let expr_span = expr.span;
+            let ctxt = expr.span.ctxt();
 
             // if/while let ... = ... { ... }
-            //                 ^^^
-            let op_span = result_expr.span.source_callsite();
+            //                    ^^^
+            let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else {
+                return;
+            };
 
             // if/while let ... = ... { ... }
-            // ^^^^^^^^^^^^^^^^^^^
-            let span = expr_span.until(op_span.shrink_to_hi());
+            // ^^^^^^^^^^^^^^^^^^^^^^
+            let span = expr_span.until(res_span.shrink_to_hi());
 
-            let app = if needs_drop {
+            let mut app = if needs_drop {
                 Applicability::MaybeIncorrect
             } else {
                 Applicability::MachineApplicable
             };
 
-            let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_")
+            let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app)
                 .maybe_par()
                 .to_string();
 
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 19b49c44d57..ad47c13896c 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -67,8 +67,10 @@ fn report_single_pattern(
     els: Option<&Expr<'_>>,
 ) {
     let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
+    let ctxt = expr.span.ctxt();
+    let mut app = Applicability::HasPlaceholders;
     let els_str = els.map_or(String::new(), |els| {
-        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
+        format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
     });
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
@@ -103,7 +105,7 @@ fn report_single_pattern(
                 // PartialEq for different reference counts may not exist.
                 "&".repeat(ref_count_diff),
                 snippet(cx, arms[0].pat.span, ".."),
-                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
+                expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
             );
             (msg, sugg)
         } else {
@@ -112,21 +114,13 @@ fn report_single_pattern(
                 "if let {} = {} {}{els_str}",
                 snippet(cx, arms[0].pat.span, ".."),
                 snippet(cx, ex.span, ".."),
-                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
+                expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
             );
             (msg, sugg)
         }
     };
 
-    span_lint_and_sugg(
-        cx,
-        lint,
-        expr.span,
-        msg,
-        "try this",
-        sugg,
-        Applicability::HasPlaceholders,
-    );
+    span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app);
 }
 
 fn check_opt_like<'a>(
diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs
index 8e1130cf8df..00853348840 100644
--- a/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -1,6 +1,6 @@
 use super::{contains_return, BIND_INSTEAD_OF_MAP};
 use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_with_macro_callsite};
+use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -76,11 +76,8 @@ pub(crate) trait BindInsteadOfMap {
             if !contains_return(inner_expr);
             if let Some(msg) = Self::lint_msg(cx);
             then {
-                let some_inner_snip = if inner_expr.span.from_expansion() {
-                    snippet_with_macro_callsite(cx, inner_expr.span, "_")
-                } else {
-                    snippet(cx, inner_expr.span, "_")
-                };
+                let mut app = Applicability::MachineApplicable;
+                let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0;
 
                 let closure_args_snip = snippet(cx, closure_args_span, "..");
                 let option_snip = snippet(cx, recv.span, "..");
@@ -92,7 +89,7 @@ pub(crate) trait BindInsteadOfMap {
                     &msg,
                     "try this",
                     note,
-                    Applicability::MachineApplicable,
+                    app,
                 );
                 true
             } else {
diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 355f53532e2..5e8ad0861f3 100644
--- a/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths;
-use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{is_type_diagnostic_item, match_type};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -33,7 +33,9 @@ pub(super) fn check(
             return;
         };
 
-        let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
+        // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+        let mut app = Applicability::Unspecified;
+        let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
 
         span_lint_and_sugg(
             cx,
@@ -42,7 +44,7 @@ pub(super) fn check(
             "using `.clone()` on a ref-counted pointer",
             "try this",
             format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
-            Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+            app,
         );
     }
 }
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 4460f38fcc1..7ce28ea93e0 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
-use clippy_utils::source::{snippet, snippet_with_macro_callsite};
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{contains_return, is_trait_item, last_path_segment};
 use if_chain::if_chain;
@@ -9,7 +9,6 @@ use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
-use std::borrow::Cow;
 
 use super::OR_FUN_CALL;
 
@@ -111,37 +110,24 @@ pub(super) fn check<'tcx>(
             if poss.contains(&name);
 
             then {
+                let ctxt = span.ctxt();
+                let mut app = Applicability::HasPlaceholders;
                 let sugg = {
                     let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
                         (false, Some(fun_span)) => (fun_span, false),
                         _ => (arg.span, true),
                     };
 
-                    let format_span = |span: Span| {
-                        let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, "..");
-                        let snip = if not_macro_argument_snippet == "vec![]" {
-                            let macro_expanded_snipped = snippet(cx, snippet_span, "..");
-                            match macro_expanded_snipped.strip_prefix("$crate::vec::") {
-                                Some(stripped) => Cow::Owned(stripped.to_owned()),
-                                None => macro_expanded_snipped,
-                            }
-                        } else {
-                            not_macro_argument_snippet
-                        };
-
-                        snip.to_string()
-                    };
-
-                    let snip = format_span(snippet_span);
+                    let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0;
                     let snip = if use_lambda {
                         let l_arg = if fn_has_arguments { "_" } else { "" };
                         format!("|{l_arg}| {snip}")
                     } else {
-                        snip
+                        snip.into_owned()
                     };
 
                     if let Some(f) = second_arg {
-                        let f = format_span(f.span);
+                        let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0;
                         format!("{snip}, {f}")
                     } else {
                         snip
@@ -155,7 +141,7 @@ pub(super) fn check<'tcx>(
                     &format!("use of `{name}` followed by a function call"),
                     "try this",
                     format!("{name}_{suffix}({sugg})"),
-                    Applicability::HasPlaceholders,
+                    app,
                 );
             }
         }
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 0705029a613..3752b9a946f 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then};
-use clippy_utils::source::{snippet, snippet_opt};
+use clippy_utils::source::{snippet, snippet_opt, snippet_with_context};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
@@ -181,20 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
             if let Some(init) = local.init;
             then {
-                // use the macro callsite when the init span (but not the whole local span)
-                // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
-                let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() {
-                    Sugg::hir_with_macro_callsite(cx, init, "..")
-                } else {
-                    Sugg::hir(cx, init, "..")
-                };
+                let ctxt = local.span.ctxt();
+                let mut app = Applicability::MachineApplicable;
+                let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
                 let (mutopt, initref) = if mutabl == Mutability::Mut {
                     ("mut ", sugg_init.mut_addr())
                 } else {
                     ("", sugg_init.addr())
                 };
                 let tyopt = if let Some(ty) = local.ty {
-                    format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, ".."))
+                    let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
+                    format!(": &{mutopt}{ty_snip}")
                 } else {
                     String::new()
                 };
@@ -212,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
                                 "let {name}{tyopt} = {initref};",
                                 name=snippet(cx, name.span, ".."),
                             ),
-                            Applicability::MachineApplicable,
+                            app,
                         );
                     }
                 );
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index 8aa814b7405..309f67521a3 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::is_interior_mut_ty;
 use clippy_utils::{def_path_def_ids, trait_ref_of_method};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
+use rustc_middle::query::Key;
+use rustc_middle::ty::{Adt, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -153,53 +154,18 @@ impl MutableKeyType {
             let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
                 .iter()
                 .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
-            if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) {
-                span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
+            if !is_keyed_type {
+                return;
             }
-        }
-    }
 
-    /// Determines if a type contains interior mutability which would affect its implementation of
-    /// [`Hash`] or [`Ord`].
-    fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-        match *ty.kind() {
-            Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
-            Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
-            Array(inner_ty, size) => {
-                size.try_eval_target_usize(cx.tcx, cx.param_env)
-                    .map_or(true, |u| u != 0)
-                    && self.is_interior_mutable_type(cx, inner_ty)
-            },
-            Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
-            Adt(def, substs) => {
-                // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
-                // that of their type parameters.  Note: we don't include `HashSet` and `HashMap`
-                // because they have no impl for `Hash` or `Ord`.
-                let def_id = def.did();
-                let is_std_collection = [
-                    sym::Option,
-                    sym::Result,
-                    sym::LinkedList,
-                    sym::Vec,
-                    sym::VecDeque,
-                    sym::BTreeMap,
-                    sym::BTreeSet,
-                    sym::Rc,
-                    sym::Arc,
-                ]
-                .iter()
-                .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
-                let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
-                if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) {
-                    // The type is mutable if any of its type parameters are
-                    substs.types().any(|ty| self.is_interior_mutable_type(cx, ty))
-                } else {
-                    !ty.has_escaping_bound_vars()
-                        && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
-                        && !ty.is_freeze(cx.tcx, cx.param_env)
-                }
-            },
-            _ => false,
+            let subst_ty = substs.type_at(0);
+            // Determines if a type contains interior mutability which would affect its implementation of
+            // [`Hash`] or [`Ord`].
+            if is_interior_mut_ty(cx, subst_ty)
+                && !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
+            {
+                span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
+            }
         }
     }
 }
diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs
index a4eec95b371..c87059bf61d 100644
--- a/clippy_lints/src/needless_bool.rs
+++ b/clippy_lints/src/needless_bool.rs
@@ -340,18 +340,11 @@ fn suggest_bool_comparison<'a, 'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'_>,
     expr: &Expr<'_>,
-    mut applicability: Applicability,
+    mut app: Applicability,
     message: &str,
     conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
 ) {
-    let hint = if expr.span.from_expansion() {
-        if applicability != Applicability::Unspecified {
-            applicability = Applicability::MaybeIncorrect;
-        }
-        Sugg::hir_with_macro_callsite(cx, expr, "..")
-    } else {
-        Sugg::hir_with_applicability(cx, expr, "..", &mut applicability)
-    };
+    let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app);
     span_lint_and_sugg(
         cx,
         BOOL_COMPARISON,
@@ -359,7 +352,7 @@ fn suggest_bool_comparison<'a, 'tcx>(
         message,
         "try simplifying it as shown",
         conv_hint(hint).to_string(),
-        applicability,
+        app,
     );
 }
 
diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs
index bc64ccb295c..8fd9ae351a0 100644
--- a/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -1,9 +1,10 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Pos};
 use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
@@ -38,25 +39,28 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
             let attrs = cx.tcx.hir().attrs(item.hir_id());
-            let mut applicability = Applicability::MachineApplicable;
-            let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability);
+            let mut app = Applicability::MaybeIncorrect;
+            let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app);
             for attr in attrs {
                 if let Some(ident) = attr.ident()
                     && ident.name == rustc_span::sym::no_mangle
                     && fn_sig.header.abi == Abi::Rust
-                    && !snippet.contains("extern") {
+                    && let Some((fn_attrs, _)) = snippet.split_once("fn")
+                    && !fn_attrs.contains("extern")
+                {
+                    let sugg_span = fn_sig.span
+                        .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
+                        .shrink_to_lo();
 
-                    let suggestion = snippet.split_once("fn")
-                        .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#));
-
-                    span_lint_and_sugg(
+                    span_lint_and_then(
                         cx,
                         NO_MANGLE_WITH_RUST_ABI,
                         fn_sig.span,
-                        "attribute #[no_mangle] set on a Rust ABI function",
-                        "try",
-                        suggestion,
-                        applicability
+                        "`#[no_mangle]` set on a function with the default (`Rust`) ABI",
+                        |diag| {
+                            diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app)
+                                .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app);
+                        },
                     );
                 }
             }
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index c5ea09590d3..bbbcda069c5 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -12,6 +12,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::SyntaxContext;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -95,10 +96,10 @@ struct OptionOccurrence {
     none_expr: String,
 }
 
-fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
+fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String {
     format!(
         "{}{}",
-        Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(),
+        cond_sugg.maybe_par(),
         if as_mut {
             ".as_mut()"
         } else if as_ref {
@@ -111,6 +112,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
 
 fn try_get_option_occurrence<'tcx>(
     cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
     pat: &Pat<'tcx>,
     expr: &Expr<'_>,
     if_then: &'tcx Expr<'_>,
@@ -160,11 +162,23 @@ fn try_get_option_occurrence<'tcx>(
                 }
             }
 
+            let mut app = Applicability::Unspecified;
             return Some(OptionOccurrence {
-                option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
+                option: format_option_in_sugg(
+                    Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app),
+                    as_ref,
+                    as_mut,
+                ),
                 method_sugg: method_sugg.to_string(),
-                some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")),
-                none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")),
+                some_expr: format!(
+                    "|{capture_mut}{capture_name}| {}",
+                    Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app),
+                ),
+                none_expr: format!(
+                    "{}{}",
+                    if method_sugg == "map_or" { "" } else { "|| " },
+                    Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app),
+                ),
             });
         }
     }
@@ -194,7 +208,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
     }) = higher::IfLet::hir(cx, expr)
     {
         if !is_else_clause(cx.tcx, expr) {
-            return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else);
+            return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else);
         }
     }
     None
@@ -203,7 +217,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
 fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurrence> {
     if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
         if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) {
-            return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else);
+            return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else);
         }
     }
     None
diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs
index 27ad4308637..2d30e77d55d 100644
--- a/clippy_lints/src/redundant_async_block.rs
+++ b/clippy_lints/src/redundant_async_block.rs
@@ -1,5 +1,5 @@
 use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
-use rustc_ast::ast::*;
+use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
 use rustc_ast::visit::Visitor as AstVisitor;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.69.0"]
     pub REDUNDANT_ASYNC_BLOCK,
-    complexity,
+    nursery,
     "`async { future.await }` can be replaced by `future`"
 }
 declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]);
@@ -48,6 +48,11 @@ impl EarlyLintPass for RedundantAsyncBlock {
             !future.span.from_expansion() &&
             !await_in_expr(future)
         {
+            if captures_value(last) {
+                // If the async block captures variables then there is no equivalence.
+                return;
+            }
+
             span_lint_and_sugg(
                 cx,
                 REDUNDANT_ASYNC_BLOCK,
@@ -82,3 +87,33 @@ impl<'ast> AstVisitor<'ast> for AwaitDetector {
         }
     }
 }
+
+/// Check whether an expression may have captured a local variable.
+/// This is done by looking for paths with only one segment, except as
+/// a prefix of `.await` since this would be captured by value.
+///
+/// This function will sometimes return `true` even tough there are no
+/// captures happening: at the AST level, it is impossible to
+/// dinstinguish a function call from a call to a closure which comes
+/// from the local environment.
+fn captures_value(expr: &Expr) -> bool {
+    let mut detector = CaptureDetector::default();
+    detector.visit_expr(expr);
+    detector.capture_found
+}
+
+#[derive(Default)]
+struct CaptureDetector {
+    capture_found: bool,
+}
+
+impl<'ast> AstVisitor<'ast> for CaptureDetector {
+    fn visit_expr(&mut self, ex: &'ast Expr) {
+        match (&ex.kind, self.capture_found) {
+            (ExprKind::Await(fut), _) if matches!(fut.kind, ExprKind::Path(..)) => (),
+            (ExprKind::Path(_, path), _) if path.segments.len() == 1 => self.capture_found = true,
+            (_, false) => rustc_ast::visit::walk_expr(self, ex),
+            _ => (),
+        }
+    }
+}
diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs
index 66638eed998..355f907e257 100644
--- a/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -1,7 +1,6 @@
 use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::sugg;
+use clippy_utils::source::snippet_with_context;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, ExprKind};
@@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
             if let Some(expr) = block.expr;
             let t_expr = cx.typeck_results().expr_ty(expr);
             if t_expr.is_unit();
-            if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
+            let mut app = Applicability::MaybeIncorrect;
+            if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0;
             if !snippet.ends_with('}') && !snippet.ends_with(';');
             if cx.sess().source_map().is_multiline(block.span);
             then {
@@ -52,17 +52,14 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
                 if let ExprKind::DropTemps(..) = &expr.kind {
                     return;
                 }
-
-                let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, "..");
-                let suggestion = format!("{sugg};");
                 span_lint_and_sugg(
                     cx,
                     SEMICOLON_IF_NOTHING_RETURNED,
                     expr.span.source_callsite(),
                     "consider adding a `;` to the last statement for consistent formatting",
                     "add a `;` here",
-                    suggestion,
-                    Applicability::MaybeIncorrect,
+                    format!("{snippet};"),
+                    app,
                 );
             }
         }
diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs
index e12681c0a0c..869358fb1ba 100644
--- a/clippy_lints/src/significant_drop_tightening.rs
+++ b/clippy_lints/src/significant_drop_tightening.rs
@@ -1,9 +1,9 @@
-use crate::FxHashSet;
 use clippy_utils::{
     diagnostics::span_lint_and_then,
     get_attr,
     source::{indent_of, snippet},
 };
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::{
     self as hir,
@@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
 pub struct SignificantDropTightening<'tcx> {
     /// Auxiliary structure used to avoid having to verify the same type multiple times.
     seen_types: FxHashSet<Ty<'tcx>>,
+    type_cache: FxHashMap<Ty<'tcx>, bool>,
 }
 
 impl<'tcx> SignificantDropTightening<'tcx> {
@@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> {
         stmt: &hir::Stmt<'_>,
         cb: impl Fn(&mut SigDropAuxParams),
     ) {
-        let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types);
+        let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache);
         sig_drop_finder.visit_expr(expr);
         if sig_drop_finder.has_sig_drop {
             cb(sdap);
@@ -296,15 +297,24 @@ impl Default for SigDropAuxParams {
 struct SigDropChecker<'cx, 'sdt, 'tcx> {
     cx: &'cx LateContext<'tcx>,
     seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+    type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
 }
 
 impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
-    pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
+    pub(crate) fn new(
+        cx: &'cx LateContext<'tcx>,
+        seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+        type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+    ) -> Self {
         seen_types.clear();
-        Self { cx, seen_types }
+        Self {
+            cx,
+            seen_types,
+            type_cache,
+        }
     }
 
-    pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+    pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
         if let Some(adt) = ty.ty_adt_def() {
             let mut iter = get_attr(
                 self.cx.sess(),
@@ -340,6 +350,16 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
         }
     }
 
+    pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+        // The borrow checker prevents us from using something fancier like or_insert_with.
+        if let Some(ty) = self.type_cache.get(&ty) {
+            return *ty;
+        }
+        let value = self.has_sig_drop_attr_uncached(ty);
+        self.type_cache.insert(ty, value);
+        value
+    }
+
     fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
         !self.seen_types.insert(ty)
     }
@@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> {
 }
 
 impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
-    fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
+    fn new(
+        cx: &'cx LateContext<'tcx>,
+        seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+        type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+    ) -> Self {
         Self {
             cx,
             has_sig_drop: false,
-            sig_drop_checker: SigDropChecker::new(cx, seen_types),
+            sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache),
         }
     }
 }
diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs
index 1aeac724ab1..f7eef03d1d4 100644
--- a/clippy_lints/src/swap.rs
+++ b/clippy_lints/src/swap.rs
@@ -6,7 +6,8 @@ use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core}
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
@@ -188,8 +189,10 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
         if let Some((lhs0, rhs0)) = parse(first)
             && let Some((lhs1, rhs1)) = parse(second)
             && first.span.eq_ctxt(second.span)
+			&& !in_external_macro(cx.sess(), first.span)
             && is_same(cx, lhs0, rhs1)
             && is_same(cx, lhs1, rhs0)
+			&& !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421)
             && let Some(lhs_sugg) = match &lhs0 {
                 ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr),
                 ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())),
@@ -257,8 +260,8 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<
 /// Implementation of the xor case for `MANUAL_SWAP` lint.
 fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
     for [s1, s2, s3] in block.stmts.array_windows::<3>() {
+        let ctxt = s1.span.ctxt();
         if_chain! {
-            let ctxt = s1.span.ctxt();
             if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt);
             if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt);
             if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt);
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index 3430b6e3734..cc7c2b039f2 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_node;
-use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
@@ -52,12 +52,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
                 "this let-binding has unit value",
                 |diag| {
                     if let Some(expr) = &local.init {
-                        let snip = snippet_with_macro_callsite(cx, expr.span, "()");
+                        let mut app = Applicability::MachineApplicable;
+                        let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0;
                         diag.span_suggestion(
                             local.span,
                             "omit the `let` binding",
                             format!("{snip};"),
-                            Applicability::MachineApplicable, // snippet
+                            app,
                         );
                     }
                 },
diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs
new file mode 100644
index 00000000000..af0b4b1592f
--- /dev/null
+++ b/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -0,0 +1,84 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for initialization of a `struct` by copying a base without setting
+    /// any field.
+    ///
+    /// ### Why is this bad?
+    /// Readibility suffers from unnecessary struct building.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct S { s: String }
+    ///
+    /// let a = S { s: String::from("Hello, world!") };
+    /// let b = S { ..a };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct S { s: String }
+    ///
+    /// let a = S { s: String::from("Hello, world!") };
+    /// let b = a;
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub UNNECESSARY_STRUCT_INITIALIZATION,
+    complexity,
+    "struct built from a base that can be written mode concisely"
+}
+declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]);
+
+impl LateLintPass<'_> for UnnecessaryStruct {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if let ExprKind::Struct(_, &[], Some(base)) = expr.kind {
+            if let Some(parent) = get_parent_expr(cx, expr) &&
+                let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) &&
+                parent_ty.is_any_ptr()
+            {
+                if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() {
+                    // When the type implements `Copy`, a reference to the new struct works on the
+                    // copy. Using the original would borrow it.
+                    return;
+                }
+
+                if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) {
+                    // The original can be used in a mutable reference context only if it is mutable.
+                    return;
+                }
+            }
+
+            // TODO: do not propose to replace *XX if XX is not Copy
+            if let ExprKind::Unary(UnOp::Deref, target) = base.kind &&
+                matches!(target.kind, ExprKind::Path(..)) &&
+                !is_copy(cx, cx.typeck_results().expr_ty(expr))
+            {
+                // `*base` cannot be used instead of the struct in the general case if it is not Copy.
+                return;
+            }
+
+            span_lint_and_sugg(
+                cx,
+                UNNECESSARY_STRUCT_INITIALIZATION,
+                expr.span,
+                "unnecessary struct building",
+                "replace with",
+                snippet(cx, base.span, "..").into_owned(),
+                rustc_errors::Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(hir_id) = path_to_local(expr) &&
+        let Node::Pat(pat) = cx.tcx.hir().get(hir_id)
+    {
+        matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..))
+    } else {
+        true
+    }
+}
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index fede625f72a..ddbe6b2c790 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
-use clippy_utils::source::{snippet, snippet_with_macro_callsite};
+use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
@@ -68,15 +68,16 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
-                        let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string();
+                        let mut app = Applicability::MachineApplicable;
+                        let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "<expr>", &mut app).0;
                         span_lint_and_sugg(
                             cx,
                             USELESS_CONVERSION,
                             e.span,
                             &format!("useless conversion to the same type: `{b}`"),
                             "consider removing `.into()`",
-                            sugg,
-                            Applicability::MachineApplicable, // snippet
+                            sugg.into_owned(),
+                            app,
                         );
                     }
                 }
@@ -165,7 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             if same_type_and_consts(a, b);
 
                             then {
-                                let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par();
+                                let mut app = Applicability::MachineApplicable;
+                                let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_par();
                                 let sugg_msg =
                                     format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                 span_lint_and_sugg(
@@ -175,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                                     &format!("useless conversion to the same type: `{b}`"),
                                     &sugg_msg,
                                     sugg.to_string(),
-                                    Applicability::MachineApplicable, // snippet
+                                    app,
                                 );
                             }
                         }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 1c7f3e96db8..8ba252425a3 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -437,7 +437,7 @@ define_Conf! {
     ///
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     (large_error_threshold: u64 = 128),
-    /// Lint: MUTABLE_KEY_TYPE.
+    /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND.
     ///
     /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
     /// for the generic parameters for determining interior mutability
diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index e105452e1c5..36f910c983f 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -158,12 +158,10 @@ impl LateLintPass<'_> for WildcardImports {
                 let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(false);
                 let imports_string = if imports.len() == 1 {
                     imports.pop().unwrap()
+                } else if braced_glob {
+                    imports.join(", ")
                 } else {
-                    if braced_glob {
-                        imports.join(", ")
-                    } else {
-                        format!("{{{}}}", imports.join(", "))
-                    }
+                    format!("{{{}}}", imports.join(", "))
                 };
 
                 let sugg = if braced_glob {