about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/Cargo.lock8
-rw-r--r--src/tools/rust-analyzer/Cargo.toml38
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs175
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs79
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs24
-rw-r--r--[-rwxr-xr-x]src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs0
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs124
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs22
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs55
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs27
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs1
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json6
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs8
44 files changed, 645 insertions, 314 deletions
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 5a29379ba48..80a311a74ab 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1294,7 +1294,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "lsp-server"
-version = "0.7.8"
+version = "0.7.9"
 dependencies = [
  "anyhow",
  "crossbeam-channel",
@@ -1310,9 +1310,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-server"
-version = "0.7.8"
+version = "0.7.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9462c4dc73e17f971ec1f171d44bfffb72e65a130117233388a0ebc7ec5656f9"
+checksum = "7d6ada348dbc2703cbe7637b2dda05cff84d3da2819c24abcb305dd613e0ba2e"
 dependencies = [
  "crossbeam-channel",
  "log",
@@ -2007,7 +2007,7 @@ dependencies = [
  "intern",
  "itertools 0.14.0",
  "load-cargo",
- "lsp-server 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lsp-server 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-types",
  "memchr",
  "mimalloc",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index e7cf0212bf2..01a13a39f7b 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -100,7 +100,7 @@ ra-ap-rustc_pattern_analysis = { version = "0.123", default-features = false }
 # in-tree crates that are published separately and follow semver. See lib/README.md
 line-index = { version = "0.1.2" }
 la-arena = { version = "0.3.1" }
-lsp-server = { version = "0.7.8" }
+lsp-server = { version = "0.7.9" }
 
 # non-local crates
 anyhow = "1.0.98"
@@ -125,11 +125,11 @@ memmap2 = "0.9.5"
 nohash-hasher = "0.2.0"
 oorandom = "11.1.5"
 object = { version = "0.36.7", default-features = false, features = [
-  "std",
-  "read_core",
-  "elf",
-  "macho",
-  "pe",
+    "std",
+    "read_core",
+    "elf",
+    "macho",
+    "pe",
 ] }
 process-wrap = { version = "8.2.1", features = ["std"] }
 pulldown-cmark-to-cmark = "10.0.4"
@@ -139,9 +139,9 @@ rowan = "=0.15.15"
 # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
 # on impls without it
 salsa = { version = "0.23.0", default-features = true, features = [
-  "rayon",
-  "salsa_unstable",
-  "macros",
+    "rayon",
+    "salsa_unstable",
+    "macros",
 ] }
 salsa-macros = "0.23.0"
 semver = "1.0.26"
@@ -151,9 +151,9 @@ serde_json = "1.0.140"
 rustc-hash = "2.1.1"
 rustc-literal-escaper = "0.0.4"
 smallvec = { version = "1.15.1", features = [
-  "const_new",
-  "union",
-  "const_generics",
+    "const_new",
+    "union",
+    "const_generics",
 ] }
 smol_str = "0.3.2"
 temp-dir = "0.1.16"
@@ -161,12 +161,12 @@ text-size = "1.1.1"
 tracing = "0.1.41"
 tracing-tree = "0.4.0"
 tracing-subscriber = { version = "0.3.19", default-features = false, features = [
-  "registry",
-  "fmt",
-  "local-time",
-  "std",
-  "time",
-  "tracing-log",
+    "registry",
+    "fmt",
+    "local-time",
+    "std",
+    "time",
+    "tracing-log",
 ] }
 triomphe = { version = "0.1.14", default-features = false, features = ["std"] }
 url = "2.5.4"
@@ -176,7 +176,7 @@ xshell = "0.2.7"
 dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] }
 # We need to freeze the version of the crate, as it needs to match with dashmap
 hashbrown = { version = "0.14.*", features = [
-  "inline-more",
+    "inline-more",
 ], default-features = false }
 
 [workspace.lints.rust]
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index d207305b4c6..05f06f97fdc 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1241,29 +1241,27 @@ impl<'db> SemanticsImpl<'db> {
                                         adt,
                                     ))
                                 })?;
-                            let mut res = None;
                             for (_, derive_attr, derives) in derives {
                                 // as there may be multiple derives registering the same helper
                                 // name, we gotta make sure to call this for all of them!
                                 // FIXME: We need to call `f` for all of them as well though!
-                                res = res.or(process_expansion_for_token(
-                                    ctx,
-                                    &mut stack,
-                                    derive_attr,
-                                ));
+                                process_expansion_for_token(ctx, &mut stack, derive_attr);
                                 for derive in derives.into_iter().flatten() {
-                                    res = res
-                                        .or(process_expansion_for_token(ctx, &mut stack, derive));
+                                    process_expansion_for_token(ctx, &mut stack, derive);
                                 }
                             }
                             // remove all tokens that are within the derives expansion
                             filter_duplicates(tokens, adt.syntax().text_range());
-                            Some(res)
+                            Some(())
                         });
                         // if we found derives, we can early exit. There is no way we can be in any
                         // macro call at this point given we are not in a token tree
-                        if let Some(res) = res {
-                            return res;
+                        if let Some(()) = res {
+                            // Note: derives do not remap the original token. Furthermore, we want
+                            // the original token to be before the derives in the list, because if they
+                            // upmap to the same token and we deduplicate them (e.g. in rename), we
+                            // want the original token to remain, not the derive.
+                            return None;
                         }
                     }
                     // Then check for token trees, that means we are either in a function-like macro or
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index f73b8c4fd0f..c208c8bf789 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -13,12 +13,7 @@ use ide_db::{
 use itertools::Itertools;
 use syntax::{
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
-    ast::{
-        self, HasName,
-        edit::IndentLevel,
-        edit_in_place::{AttrsOwnerEdit, Indent},
-        make,
-    },
+    ast::{self, HasName, edit::IndentLevel, edit_in_place::Indent, make},
 };
 
 use crate::{
@@ -506,18 +501,6 @@ fn node_to_insert_before(target_node: SyntaxNode) -> SyntaxNode {
 }
 
 fn make_bool_enum(make_pub: bool) -> ast::Enum {
-    let enum_def = make::enum_(
-        if make_pub { Some(make::visibility_pub()) } else { None },
-        make::name("Bool"),
-        None,
-        None,
-        make::variant_list(vec![
-            make::variant(None, make::name("True"), None, None),
-            make::variant(None, make::name("False"), None, None),
-        ]),
-    )
-    .clone_for_update();
-
     let derive_eq = make::attr_outer(make::meta_token_tree(
         make::ext::ident_path("derive"),
         make::token_tree(
@@ -529,11 +512,19 @@ fn make_bool_enum(make_pub: bool) -> ast::Enum {
                 NodeOrToken::Token(make::tokens::ident("Eq")),
             ],
         ),
-    ))
-    .clone_for_update();
-    enum_def.add_attr(derive_eq);
-
-    enum_def
+    ));
+    make::enum_(
+        [derive_eq],
+        if make_pub { Some(make::visibility_pub()) } else { None },
+        make::name("Bool"),
+        None,
+        None,
+        make::variant_list(vec![
+            make::variant(None, make::name("True"), None, None),
+            make::variant(None, make::name("False"), None, None),
+        ]),
+    )
+    .clone_for_update()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index 916bb67ebb4..5f526ec8994 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -236,6 +236,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
             };
             let mut fn_ = make::fn_(
                 None,
+                None,
                 closure_name_or_default.clone(),
                 closure_type_params,
                 closure_where_clause,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
index f1cc3d90b9c..7d8b763d8b8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs
@@ -96,6 +96,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
             }
 
             let error_type = ast::AssocItem::TypeAlias(make::ty_alias(
+                None,
                 "Error",
                 None,
                 None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index 66552dd65f5..4b6d0b37854 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -9,7 +9,6 @@ use stdx::never;
 use syntax::{
     AstNode, Direction, SyntaxNode, SyntaxToken, T,
     ast::{self, Use, UseTree, VisibilityKind, make},
-    ted,
 };
 
 use crate::{
@@ -165,8 +164,6 @@ fn build_expanded_import(
     let filtered_defs =
         if reexport_public_items { refs_in_target } else { refs_in_target.used_refs(ctx) };
 
-    let use_tree = builder.make_mut(use_tree);
-
     let names_to_import = find_names_to_import(filtered_defs, imported_defs);
     let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
         let path = make::ext::ident_path(
@@ -176,22 +173,24 @@ fn build_expanded_import(
     }))
     .clone_for_update();
 
+    let mut editor = builder.make_editor(use_tree.syntax());
     match use_tree.star_token() {
         Some(star) => {
             let needs_braces = use_tree.path().is_some() && names_to_import.len() != 1;
             if needs_braces {
-                ted::replace(star, expanded.syntax())
+                editor.replace(star, expanded.syntax())
             } else {
                 let without_braces = expanded
                     .syntax()
                     .children_with_tokens()
                     .filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
                     .collect();
-                ted::replace_with_many(star, without_braces)
+                editor.replace_with_many(star, without_braces)
             }
         }
         None => never!(),
     }
+    builder.add_file_edits(ctx.vfs_file_id(), editor);
 }
 
 fn get_export_visibility_kind(use_item: &Use) -> VisibilityKind {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 890b8dd6412..d88e3311bd7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -1642,6 +1642,7 @@ fn format_function(
 
     make::fn_(
         None,
+        None,
         fun_name,
         generic_params,
         where_clause,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
index c6a6b97df82..e783b869345 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
@@ -1,6 +1,5 @@
-use std::iter;
+use std::ops::RangeInclusive;
 
-use either::Either;
 use hir::{HasSource, ModuleSource};
 use ide_db::{
     FileId, FxHashMap, FxHashSet,
@@ -82,7 +81,15 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         curr_parent_module = ast::Module::cast(mod_syn_opt);
     }
 
-    let mut module = extract_target(&node, ctx.selection_trimmed())?;
+    let selection_range = ctx.selection_trimmed();
+    let (mut module, module_text_range) = if let Some(item) = ast::Item::cast(node.clone()) {
+        let module = extract_single_target(&item);
+        (module, node.text_range())
+    } else {
+        let (module, range) = extract_child_target(&node, selection_range)?;
+        let module_text_range = range.start().text_range().cover(range.end().text_range());
+        (module, module_text_range)
+    };
     if module.body_items.is_empty() {
         return None;
     }
@@ -92,7 +99,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     acc.add(
         AssistId::refactor_extract("extract_module"),
         "Extract Module",
-        module.text_range,
+        module_text_range,
         |builder| {
             //This takes place in three steps:
             //
@@ -110,17 +117,17 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
             //for change_visibility and usages for first point mentioned above in the process
 
             let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) =
-                module.get_usages_and_record_fields(ctx);
+                module.get_usages_and_record_fields(ctx, module_text_range);
 
             builder.edit_file(ctx.vfs_file_id());
             use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| {
                 builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}"));
             });
 
-            let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx);
+            let import_items = module.resolve_imports(curr_parent_module, ctx);
             module.change_visibility(record_fields);
 
-            let module_def = generate_module_def(&impl_parent, &mut module, old_item_indent);
+            let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string();
 
             let mut usages_to_be_processed_for_cur_file = vec![];
             for (file_id, usages) in usages_to_be_processed {
@@ -157,15 +164,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
                 builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
             } else {
-                for import_path_text_range in import_paths_to_be_removed {
-                    if module.text_range.intersect(import_path_text_range).is_some() {
-                        module.text_range = module.text_range.cover(import_path_text_range);
-                    } else {
-                        builder.delete(import_path_text_range);
+                for import_item in import_items {
+                    if !module_text_range.contains_range(import_item) {
+                        builder.delete(import_item);
                     }
                 }
-
-                builder.replace(module.text_range, module_def)
+                builder.replace(module_text_range, module_def)
             }
         },
     )
@@ -173,38 +177,50 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
 fn generate_module_def(
     parent_impl: &Option<ast::Impl>,
-    module: &mut Module,
+    module: Module,
     old_indent: IndentLevel,
-) -> String {
-    let (items_to_be_processed, new_item_indent) = if parent_impl.is_some() {
-        (Either::Left(module.body_items.iter()), old_indent + 2)
+) -> ast::Module {
+    let Module { name, body_items, use_items } = module;
+    let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) {
+        let assoc_items = body_items
+            .into_iter()
+            .map(|item| item.syntax().clone())
+            .filter_map(ast::AssocItem::cast)
+            .map(|it| it.indent(IndentLevel(1)))
+            .collect_vec();
+        let assoc_item_list = make::assoc_item_list(Some(assoc_items));
+        let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list));
+        // Add the import for enum/struct corresponding to given impl block
+        let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax());
+        let mut module_body_items = use_items;
+        module_body_items.insert(0, use_impl);
+        module_body_items.push(ast::Item::Impl(impl_));
+        module_body_items
     } else {
-        (Either::Right(module.use_items.iter().chain(module.body_items.iter())), old_indent + 1)
+        [use_items, body_items].concat()
     };
 
-    let mut body = items_to_be_processed
-        .map(|item| item.indent(IndentLevel(1)))
-        .map(|item| format!("{new_item_indent}{item}"))
-        .join("\n\n");
+    let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec();
+    let module_body = make::item_list(Some(items));
 
-    if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) {
-        let impl_indent = old_indent + 1;
-        body = format!("{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}");
+    let module_name = make::name(name);
+    make::mod_(module_name, Some(module_body)).indent(old_indent)
+}
 
-        // Add the import for enum/struct corresponding to given impl block
-        module.make_use_stmt_of_node_with_super(self_ty.syntax());
-        for item in module.use_items.iter() {
-            body = format!("{impl_indent}{item}\n\n{body}");
-        }
-    }
+fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item {
+    let super_path = make::ext::ident_path("super");
+    let node_path = make::ext::ident_path(&node_syntax.to_string());
+    let use_ = make::use_(
+        None,
+        None,
+        make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
+    );
 
-    let module_name = module.name;
-    format!("mod {module_name} {{\n{body}\n{old_indent}}}")
+    ast::Item::from(use_)
 }
 
 #[derive(Debug)]
 struct Module {
-    text_range: TextRange,
     name: &'static str,
     /// All items except use items.
     body_items: Vec<ast::Item>,
@@ -214,22 +230,37 @@ struct Module {
     use_items: Vec<ast::Item>,
 }
 
-fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
+fn extract_single_target(node: &ast::Item) -> Module {
+    let (body_items, use_items) = if matches!(node, ast::Item::Use(_)) {
+        (Vec::new(), vec![node.clone()])
+    } else {
+        (vec![node.clone()], Vec::new())
+    };
+    let name = "modname";
+    Module { name, body_items, use_items }
+}
+
+fn extract_child_target(
+    node: &SyntaxNode,
+    selection_range: TextRange,
+) -> Option<(Module, RangeInclusive<SyntaxNode>)> {
     let selected_nodes = node
         .children()
         .filter(|node| selection_range.contains_range(node.text_range()))
-        .chain(iter::once(node.clone()));
-    let (use_items, body_items) = selected_nodes
         .filter_map(ast::Item::cast)
-        .partition(|item| matches!(item, ast::Item::Use(..)));
-
-    Some(Module { text_range: selection_range, name: "modname", body_items, use_items })
+        .collect_vec();
+    let start = selected_nodes.first()?.syntax().clone();
+    let end = selected_nodes.last()?.syntax().clone();
+    let (use_items, body_items): (Vec<ast::Item>, Vec<ast::Item>) =
+        selected_nodes.into_iter().partition(|item| matches!(item, ast::Item::Use(..)));
+    Some((Module { name: "modname", body_items, use_items }, start..=end))
 }
 
 impl Module {
     fn get_usages_and_record_fields(
         &self,
         ctx: &AssistContext<'_>,
+        replace_range: TextRange,
     ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>, FxHashMap<TextSize, ast::Use>)
     {
         let mut adt_fields = Vec::new();
@@ -247,7 +278,7 @@ impl Module {
                     ast::Adt(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Adt(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, replace_range,node_def, &mut refs, &mut use_stmts_to_be_inserted);
 
                             //Enum Fields are not allowed to explicitly specify pub, it is implied
                             match it {
@@ -281,30 +312,30 @@ impl Module {
                     ast::TypeAlias(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::TypeAlias(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted);
                         }
                     },
                     ast::Const(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Const(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted);
                         }
                     },
                     ast::Static(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Static(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted);
                         }
                     },
                     ast::Fn(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Function(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted);
                         }
                     },
                     ast::Macro(it) => {
                         if let Some(nod) = ctx.sema.to_def(&it) {
-                            self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx,replace_range, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted);
                         }
                     },
                     _ => (),
@@ -318,6 +349,7 @@ impl Module {
     fn expand_and_group_usages_file_wise(
         &self,
         ctx: &AssistContext<'_>,
+        replace_range: TextRange,
         node_def: Definition,
         refs_in_files: &mut FxHashMap<FileId, Vec<(TextRange, String)>>,
         use_stmts_to_be_inserted: &mut FxHashMap<TextSize, ast::Use>,
@@ -327,7 +359,7 @@ impl Module {
             syntax::NodeOrToken::Node(node) => node,
             syntax::NodeOrToken::Token(tok) => tok.parent().unwrap(), // won't panic
         };
-        let out_of_sel = |node: &SyntaxNode| !self.text_range.contains_range(node.text_range());
+        let out_of_sel = |node: &SyntaxNode| !replace_range.contains_range(node.text_range());
         let mut use_stmts_set = FxHashSet::default();
 
         for (file_id, refs) in node_def.usages(&ctx.sema).all() {
@@ -527,7 +559,8 @@ impl Module {
                     // mod -> ust_stmt transversal
                     // true  | false -> super import insertion
                     // true  | true -> super import insertion
-                    self.make_use_stmt_of_node_with_super(use_node);
+                    let super_use_node = make_use_stmt_of_node_with_super(use_node);
+                    self.use_items.insert(0, super_use_node);
                 }
                 None => {}
             }
@@ -556,7 +589,8 @@ impl Module {
 
                 use_tree_paths = Some(use_tree_str);
             } else if def_in_mod && def_out_sel {
-                self.make_use_stmt_of_node_with_super(use_node);
+                let super_use_node = make_use_stmt_of_node_with_super(use_node);
+                self.use_items.insert(0, super_use_node);
             }
         }
 
@@ -586,6 +620,7 @@ impl Module {
             if (def_out_sel || !is_item) && use_stmt_not_in_sel {
                 let use_ = make::use_(
                     None,
+                    None,
                     make::use_tree(make::join_paths(use_tree_paths), None, None, false),
                 );
                 self.use_items.insert(0, ast::Item::from(use_));
@@ -595,19 +630,6 @@ impl Module {
         import_path_to_be_removed
     }
 
-    fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item {
-        let super_path = make::ext::ident_path("super");
-        let node_path = make::ext::ident_path(&node_syntax.to_string());
-        let use_ = make::use_(
-            None,
-            make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
-        );
-
-        let item = ast::Item::from(use_);
-        self.use_items.insert(0, item.clone());
-        item
-    }
-
     fn process_use_stmt_for_import_resolve(
         &self,
         use_stmt: Option<ast::Use>,
@@ -1422,10 +1444,10 @@ $0fn foo(x: B) {}$0
             struct B {}
 
 mod modname {
-    use super::B;
-
     use super::A;
 
+    use super::B;
+
     impl A {
         pub(crate) fn foo(x: B) {}
     }
@@ -1737,4 +1759,27 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn test_miss_select_item() {
+        check_assist(
+            extract_module,
+            r#"
+mod foo {
+    mod $0bar {
+        fn foo(){}$0
+    }
+}
+"#,
+            r#"
+mod foo {
+    mod modname {
+        pub(crate) mod bar {
+            fn foo(){}
+        }
+    }
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
index 79f22381952..7f93506685e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
@@ -69,8 +69,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             edit.replace(ty.syntax(), new_ty.syntax());
 
             // Insert new alias
-            let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None)))
-                .clone_for_update();
+            let ty_alias =
+                make::ty_alias(None, "Type", generic_params, None, None, Some((ty, None)))
+                    .clone_for_update();
 
             if let Some(cap) = ctx.config.snippet_cap
                 && let Some(name) = ty_alias.name()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index c9c1969b9e0..bd88e8b09ce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -200,7 +200,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                     }
                     ExtractionKind::Constant => {
                         let ast_ty = make.ty(&ty_string);
-                        ast::Item::Const(make.item_const(None, pat_name, ast_ty, initializer))
+                        ast::Item::Const(make.item_const(None, None, pat_name, ast_ty, initializer))
                             .into()
                     }
                     ExtractionKind::Static => {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 2c81e2883a3..d8a2e038d33 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -155,6 +155,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                 let ret_type = method_source.ret_type();
 
                 let f = make::fn_(
+                    None,
                     vis,
                     fn_name,
                     type_params,
@@ -195,6 +196,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                         let assoc_item_list = make::assoc_item_list(Some(vec![item]));
 
                         let impl_def = make::impl_(
+                            None,
                             ty_params,
                             ty_args,
                             make::ty_path(make::ext::ident_path(name)),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index e96250f3c50..e87dde5b8e4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -20,7 +20,6 @@ use syntax::{
         HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
         WherePred,
         edit::{self, AstNodeEdit},
-        edit_in_place::AttrsOwnerEdit,
         make,
     },
     ted::{self, Position},
@@ -266,6 +265,7 @@ fn generate_impl(
             let bound_params = bound_def.generic_param_list();
 
             let delegate = make::impl_trait(
+                None,
                 delegee.is_unsafe(db),
                 bound_params.clone(),
                 bound_params.map(|params| params.to_generic_args()),
@@ -379,6 +379,7 @@ fn generate_impl(
             let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
             // 3) Generate delegate trait impl
             let delegate = make::impl_trait(
+                None,
                 trait_.is_unsafe(db),
                 trait_gen_params,
                 trait_gen_args,
@@ -652,8 +653,7 @@ fn process_assoc_item(
     qual_path_ty: ast::Path,
     base_name: &str,
 ) -> Option<ast::AssocItem> {
-    let attrs = item.attrs();
-    let assoc = match item {
+    match item {
         AssocItem::Const(c) => const_assoc_item(c, qual_path_ty),
         AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name),
         AssocItem::MacroCall(_) => {
@@ -662,18 +662,7 @@ fn process_assoc_item(
             None
         }
         AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty),
-    };
-    if let Some(assoc) = &assoc {
-        attrs.for_each(|attr| {
-            assoc.add_attr(attr.clone());
-            // fix indentations
-            if let Some(tok) = attr.syntax().next_sibling_or_token() {
-                let pos = Position::after(tok);
-                ted::insert(pos, make::tokens::whitespace("    "));
-            }
-        })
     }
-    assoc
 }
 
 fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
@@ -687,6 +676,7 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option
     // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
     let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
     let inner = make::item_const(
+        item.attrs(),
         item.visibility(),
         item.name()?,
         item.ty()?,
@@ -755,6 +745,7 @@ fn func_assoc_item(
 
     let body = make::block_expr(vec![], Some(call.into())).clone_for_update();
     let func = make::fn_(
+        item.attrs(),
         item.visibility(),
         item.name()?,
         item.generic_param_list(),
@@ -779,13 +770,14 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<Ass
     let ident = item.name()?.to_string();
 
     let alias = make::ty_alias(
+        item.attrs(),
         ident.as_str(),
         item.generic_param_list(),
         None,
         item.where_clause(),
         Some((ty, None)),
     )
-    .clone_for_update();
+    .indent(edit::IndentLevel(1));
 
     Some(AssocItem::TypeAlias(alias))
 }
@@ -1814,6 +1806,63 @@ impl T for B {
     }
 
     #[test]
+    fn test_ty_alias_attrs() {
+        check_assist(
+            generate_delegate_trait,
+            r#"
+struct A;
+
+trait T {
+    #[cfg(test)]
+    type t;
+    #[cfg(not(test))]
+    type t;
+}
+
+impl T for A {
+    #[cfg(test)]
+    type t = u32;
+    #[cfg(not(test))]
+    type t = bool;
+}
+
+struct B {
+    a$0: A,
+}
+"#,
+            r#"
+struct A;
+
+trait T {
+    #[cfg(test)]
+    type t;
+    #[cfg(not(test))]
+    type t;
+}
+
+impl T for A {
+    #[cfg(test)]
+    type t = u32;
+    #[cfg(not(test))]
+    type t = bool;
+}
+
+struct B {
+    a: A,
+}
+
+impl T for B {
+    #[cfg(test)]
+    type t = <A as T>::t;
+
+    #[cfg(not(test))]
+    type t = <A as T>::t;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn assoc_items_attributes_mutably_cloned() {
         check_assist(
             generate_delegate_trait,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
index 73a69c82fbc..06fef4af223 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_derive.rs
@@ -1,6 +1,8 @@
 use syntax::{
+    SyntaxKind::{ATTR, COMMENT, WHITESPACE},
     T,
-    ast::{self, AstNode, HasAttrs, edit_in_place::AttrsOwnerEdit, make},
+    ast::{self, AstNode, HasAttrs, edit::IndentLevel, make},
+    syntax_editor::{Element, Position},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -48,8 +50,20 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                 ))
                 .clone_for_update();
 
-                let nominal = edit.make_mut(nominal);
-                nominal.add_attr(derive.clone());
+                let mut editor = edit.make_editor(nominal.syntax());
+                let indent = IndentLevel::from_node(nominal.syntax());
+                let after_attrs_and_comments = nominal
+                    .syntax()
+                    .children_with_tokens()
+                    .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
+                    .map_or(Position::first_child_of(nominal.syntax()), Position::before);
+                editor.insert_all(
+                    after_attrs_and_comments,
+                    vec![
+                        derive.syntax().syntax_element(),
+                        make::tokens::whitespace(&format!("\n{indent}")).syntax_element(),
+                    ],
+                );
 
                 let delimiter = derive
                     .meta()
@@ -58,8 +72,9 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                     .expect("failed to get token tree out of Meta")
                     .r_paren_token()
                     .expect("make::attr_outer was expected to have a R_PAREN");
-
-                edit.add_tabstop_before_token(cap, delimiter);
+                let tabstop_before = edit.make_tabstop_before(cap);
+                editor.add_annotation(delimiter, tabstop_before);
+                edit.add_file_edits(ctx.vfs_file_id(), editor);
             }
             Some(_) => {
                 // Just move the cursor.
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index 3c327a63b0f..0b7eca2290f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -94,6 +94,7 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 // Insert new alias
                 let ty_alias = make::ty_alias(
+                    None,
                     &alias_name,
                     generic_params,
                     None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 613b32fcc16..efdb20c1e93 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -189,7 +189,7 @@ fn add_func_to_accumulator(
             )));
 
             // FIXME: adt may have generic params.
-            let impl_ = make::impl_(None, None, name, None, None).clone_for_update();
+            let impl_ = make::impl_(None, None, None, name, None, None).clone_for_update();
 
             func.indent(IndentLevel(1));
             impl_.get_or_create_assoc_item_list().add_item(func.into());
@@ -365,6 +365,7 @@ impl FunctionBuilder {
             Visibility::Pub => Some(make::visibility_pub()),
         };
         let fn_def = make::fn_(
+            None,
             visibility,
             self.fn_name,
             self.generic_param_list,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 807b9194b2d..e42d0ed1b00 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -263,6 +263,7 @@ fn generate_getter_from_info(
     let body = make::block_expr([], Some(body));
 
     make::fn_(
+        None,
         strukt.visibility(),
         fn_name,
         None,
@@ -299,6 +300,7 @@ fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldI
 
     // Make the setter fn
     make::fn_(
+        None,
         strukt.visibility(),
         fn_name,
         None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index b38ee6f7dce..77eb8efc6f6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -174,6 +174,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
             let make_impl_ = |body| {
                 make::impl_trait(
+                    None,
                     trait_.unsafe_token().is_some(),
                     None,
                     trait_gen_args.clone(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index 351f134612f..ac4a54a89ef 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -134,6 +134,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
         let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
 
         let fn_ = make::fn_(
+            None,
             strukt.visibility(),
             make::name("new"),
             None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
index 4e95ceb2e85..6076d5cb5ce 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -6,13 +6,12 @@ use ide_db::{
 };
 use syntax::{
     TokenText,
-    ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent},
+    ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent},
 };
 
 use crate::{
     AssistId,
     assist_context::{AssistContext, Assists},
-    utils::add_cfg_attrs_to,
 };
 
 // Assist: generate_single_field_struct_from
@@ -90,6 +89,7 @@ pub(crate) fn generate_single_field_struct_from(
 
             let fn_ = make::fn_(
                 None,
+                None,
                 make::name("from"),
                 None,
                 None,
@@ -110,8 +110,12 @@ pub(crate) fn generate_single_field_struct_from(
             .clone_for_update();
 
             fn_.indent(1.into());
+            let cfg_attrs = strukt
+                .attrs()
+                .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
 
             let impl_ = make::impl_trait(
+                cfg_attrs,
                 false,
                 None,
                 trait_gen_args,
@@ -128,8 +132,6 @@ pub(crate) fn generate_single_field_struct_from(
 
             impl_.get_or_create_assoc_item_list().add_item(fn_.into());
 
-            add_cfg_attrs_to(&strukt, &impl_);
-
             impl_.reindent_to(indent);
 
             builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 603be4d6673..547d3686e39 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -88,7 +88,7 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
                 }
             }
 
-            let item = make.item_const(None, make.name(&name), make.ty(&ty), initializer);
+            let item = make.item_const(None, None, make.name(&name), make.ty(&ty), initializer);
 
             if let Some((cap, name)) = ctx.config.snippet_cap.zip(item.name()) {
                 let tabstop = edit.make_tabstop_before(cap);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 9356d02706c..414f6746d44 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -112,6 +112,16 @@ fn compute_dbg_replacement(
                 }
             }
         }
+        // dbg!(2, 'x', &x, x, ...);
+        exprs if ast::ExprStmt::can_cast(parent.kind()) && exprs.iter().all(pure_expr) => {
+            let mut replace = vec![parent.clone().into()];
+            if let Some(prev_sibling) = parent.prev_sibling_or_token()
+                && prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE
+            {
+                replace.push(prev_sibling);
+            }
+            (replace, None)
+        }
         // dbg!(expr0)
         [expr] => {
             // dbg!(expr, &parent);
@@ -163,6 +173,20 @@ fn compute_dbg_replacement(
     })
 }
 
+fn pure_expr(expr: &ast::Expr) -> bool {
+    match_ast! {
+        match (expr.syntax()) {
+            ast::Literal(_) => true,
+            ast::RefExpr(it) => {
+                matches!(it.expr(), Some(ast::Expr::PathExpr(p))
+                    if p.path().and_then(|p| p.as_single_name_ref()).is_some())
+            },
+            ast::PathExpr(it) => it.path().and_then(|it| it.as_single_name_ref()).is_some(),
+            _ => false,
+        }
+    }
+}
+
 fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
     if let ast::Expr::MacroExpr(mac) = &expanded {
         // Special-case when `expanded` itself is `dbg!()` since we cannot replace the whole tree
@@ -232,6 +256,32 @@ mod tests {
     }
 
     #[test]
+    fn test_remove_simple_dbg_statement() {
+        check_assist(
+            remove_dbg,
+            r#"
+fn foo() {
+    let n = 2;
+    $0dbg!(3);
+    dbg!(2.6);
+    dbg!(1, 2.5);
+    dbg!('x');
+    dbg!(&n);
+    dbg!(n);
+    // needless comment
+    dbg!("foo");$0
+}
+"#,
+            r#"
+fn foo() {
+    let n = 2;
+    // needless comment
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_remove_dbg_not_applicable() {
         check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}");
         check_assist_not_applicable(remove_dbg, "fn main() {$0dbg(5, 6, 7)}");
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index 3cd7b58f4dd..df7057835c3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -7,11 +7,8 @@ use ide_db::{
 };
 use syntax::{
     AstNode,
-    ast::{
-        self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType,
-        make::impl_trait_type,
-    },
-    match_ast, ted,
+    ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType, make},
+    match_ast,
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -74,26 +71,31 @@ pub(crate) fn replace_named_generic_with_impl(
         "Replace named generic with impl trait",
         target,
         |edit| {
-            let type_param = edit.make_mut(type_param);
-            let fn_ = edit.make_mut(fn_);
-
-            let path_types_to_replace = path_types_to_replace
-                .into_iter()
-                .map(|param| edit.make_mut(param))
-                .collect::<Vec<_>>();
+            let mut editor = edit.make_editor(type_param.syntax());
 
             // remove trait from generic param list
             if let Some(generic_params) = fn_.generic_param_list() {
-                generic_params.remove_generic_param(ast::GenericParam::TypeParam(type_param));
-                if generic_params.generic_params().count() == 0 {
-                    ted::remove(generic_params.syntax());
+                let params: Vec<ast::GenericParam> = generic_params
+                    .clone()
+                    .generic_params()
+                    .filter(|it| it.syntax() != type_param.syntax())
+                    .collect();
+                if params.is_empty() {
+                    editor.delete(generic_params.syntax());
+                } else {
+                    let new_generic_param_list = make::generic_param_list(params);
+                    editor.replace(
+                        generic_params.syntax(),
+                        new_generic_param_list.syntax().clone_for_update(),
+                    );
                 }
             }
 
-            let new_bounds = impl_trait_type(type_bound_list);
+            let new_bounds = make::impl_trait_type(type_bound_list);
             for path_type in path_types_to_replace.iter().rev() {
-                ted::replace(path_type.syntax(), new_bounds.clone_for_update().syntax());
+                editor.replace(path_type.syntax(), new_bounds.clone_for_update().syntax());
             }
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs
index c066f41ca47..accb5c28d6e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs
@@ -1,9 +1,6 @@
 use syntax::{
     AstNode, SyntaxKind,
-    ast::{
-        self, HasAttrs, HasVisibility, edit::IndentLevel, edit_in_place::AttrsOwnerEdit, make,
-        syntax_factory::SyntaxFactory,
-    },
+    ast::{self, HasAttrs, HasVisibility, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
     syntax_editor::{Element, Position, Removable},
 };
 
@@ -46,13 +43,10 @@ pub(crate) fn unmerge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     acc.add(AssistId::refactor_rewrite("unmerge_imports"), label, target, |builder| {
         let make = SyntaxFactory::with_mappings();
         let new_use = make.use_(
+            use_.attrs(),
             use_.visibility(),
             make.use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()),
         );
-        // Add any attributes that are present on the use tree
-        use_.attrs().for_each(|attr| {
-            new_use.add_attr(attr.clone_for_update());
-        });
 
         let mut editor = builder.make_editor(use_.syntax());
         // Remove the use tree from the current use item
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 91aac9cf7b6..20e0302b57d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -736,8 +736,11 @@ fn generate_impl_inner(
         generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
     let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
 
-    let impl_ = match trait_ {
+    let cfg_attrs =
+        adt.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
+    match trait_ {
         Some(trait_) => make::impl_trait(
+            cfg_attrs,
             is_unsafe,
             None,
             None,
@@ -750,26 +753,9 @@ fn generate_impl_inner(
             adt.where_clause(),
             body,
         ),
-        None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), body),
-    }
-    .clone_for_update();
-
-    // Copy any cfg attrs from the original adt
-    add_cfg_attrs_to(adt, &impl_);
-
-    impl_
-}
-
-pub(crate) fn add_cfg_attrs_to<T, U>(from: &T, to: &U)
-where
-    T: HasAttrs,
-    U: AttrsOwnerEdit,
-{
-    let cfg_attrs =
-        from.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
-    for attr in cfg_attrs {
-        to.add_attr(attr.clone_for_update());
+        None => make::impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body),
     }
+    .clone_for_update()
 }
 
 pub(crate) fn add_method_to_adt(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 2eabf99fc69..9d246017131 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -559,6 +559,7 @@ fn expected_type_and_name<'db>(
     token: &SyntaxToken,
     name_like: &ast::NameLike,
 ) -> (Option<Type<'db>>, Option<NameOrNameRef>) {
+    let token = prev_assign_token_at_trivia(token.clone());
     let mut node = match token.parent() {
         Some(it) => it,
         None => return (None, None),
@@ -629,6 +630,17 @@ fn expected_type_and_name<'db>(
                         .map(TypeInfo::original);
                     (ty, None)
                 },
+                ast::BinExpr(it) => {
+                    if let Some(ast::BinaryOp::Assignment { op: None }) = it.op_kind() {
+                        let ty = it.lhs()
+                            .and_then(|lhs| sema.type_of_expr(&lhs))
+                            .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs)))
+                            .map(TypeInfo::original);
+                        (ty, None)
+                    } else {
+                        (None, None)
+                    }
+                },
                 ast::ArgList(_) => {
                     cov_mark::hit!(expected_type_fn_param);
                     ActiveParameter::at_token(
@@ -1856,3 +1868,23 @@ fn next_non_trivia_sibling(ele: SyntaxElement) -> Option<SyntaxElement> {
     }
     None
 }
+
+fn prev_assign_token_at_trivia(mut token: SyntaxToken) -> SyntaxToken {
+    while token.kind().is_trivia()
+        && let Some(prev) = token.prev_token()
+        && let T![=]
+        | T![+=]
+        | T![/=]
+        | T![*=]
+        | T![%=]
+        | T![>>=]
+        | T![<<=]
+        | T![-=]
+        | T![|=]
+        | T![&=]
+        | T![^=] = prev.kind()
+    {
+        token = prev
+    }
+    token
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index 75c20968e1e..7a8c70f190e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -434,3 +434,53 @@ fn f(thing: u32) -> &u32 {
         expect!["ty: u32, name: ?"],
     );
 }
+
+#[test]
+fn expected_type_assign() {
+    check_expected_type_and_name(
+        r#"
+enum State { Stop }
+fn foo() {
+    let x: &mut State = &mut State::Stop;
+    x = $0;
+}
+"#,
+        expect![[r#"ty: &'_ mut State, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_deref_assign() {
+    check_expected_type_and_name(
+        r#"
+enum State { Stop }
+fn foo() {
+    let x: &mut State = &mut State::Stop;
+    match x {
+        State::Stop => {
+            *x = $0;
+        },
+    }
+}
+"#,
+        expect![[r#"ty: State, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_deref_assign_at_block_end() {
+    check_expected_type_and_name(
+        r#"
+enum State { Stop }
+fn foo() {
+    let x: &mut State = &mut State::Stop;
+    match x {
+        State::Stop => {
+            *x = $0
+        },
+    }
+}
+"#,
+        expect![[r#"ty: State, name: ?"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index 08cd8f28608..b174adfd7e4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -194,7 +194,7 @@ fn insert_use_with_alias_option(
         use_tree = use_tree.clone_for_update();
         use_tree.wrap_in_tree_list();
     }
-    let use_item = make::use_(None, use_tree).clone_for_update();
+    let use_item = make::use_(None, None, use_tree).clone_for_update();
     for attr in
         scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
     {
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index a5d9a10d2e5..d47cc650793 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -390,7 +390,8 @@ fn get_doc_links(
 
     let (mut web_url, mut local_url) = get_doc_base_urls(db, target, target_dir, sysroot);
 
-    if let Some(path) = mod_path_of_def(db, target) {
+    let append_mod = !matches!(def, Definition::Macro(m) if m.is_macro_export(db));
+    if append_mod && let Some(path) = mod_path_of_def(db, target) {
         web_url = join_url(web_url, &path);
         local_url = join_url(local_url, &path);
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 6af156fa668..c2f08f8ca2e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -415,6 +415,30 @@ fn foo() {
 }
 
 #[test]
+fn external_docs_macro_export() {
+    check_external_docs(
+        r#"
+//- /lib.rs crate:foo
+pub mod inner {
+    #[macro_export]
+    macro_rules! my_macro {
+        () => {};
+    }
+}
+
+//- /main.rs crate:bar deps:foo
+fn main() {
+    foo::my_m$0acro!();
+}
+        "#,
+        Some("/home/user/project"),
+        Some(expect![[r#"https://docs.rs/foo/*/foo/macro.my_macro.html"#]]),
+        Some(expect![[r#"file:///home/user/project/doc/foo/macro.my_macro.html"#]]),
+        Some("/sysroot"),
+    );
+}
+
+#[test]
 fn doc_links_items_simple() {
     check_doc_links(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index ac64413effe..ac64413effe 100755..100644
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 84e41277390..f768d4b68f4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -83,14 +83,14 @@ pub(crate) fn goto_definition(
         return Some(RangeInfo::new(original_token.text_range(), navs));
     }
 
-    if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &original_token) {
-        return Some(RangeInfo::new(original_token.text_range(), navs));
-    }
-
     let navs = sema
         .descend_into_macros_no_opaque(original_token.clone(), false)
         .into_iter()
         .filter_map(|token| {
+            if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
+                return Some(navs);
+            }
+
             let parent = token.value.parent()?;
 
             let token_file_id = token.file_id;
@@ -3284,6 +3284,32 @@ fn f() {
     }
 
     #[test]
+    fn into_call_to_from_definition_within_macro() {
+        check(
+            r#"
+//- proc_macros: identity
+//- minicore: from
+struct A;
+
+struct B;
+
+impl From<A> for B {
+    fn from(value: A) -> Self {
+     //^^^^
+        B
+    }
+}
+
+#[proc_macros::identity]
+fn f() {
+    let a = A;
+    let b: B = a.into$0();
+}
+        "#,
+        );
+    }
+
+    #[test]
     fn into_call_to_from_definition_with_trait_bounds() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 7a8514c47af..8c2a2f6f72f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -228,9 +228,9 @@ fn hints(
                 chaining::hints(hints, famous_defs, config, display_target, &expr);
                 adjustment::hints(hints, famous_defs, config, display_target, &expr);
                 match expr {
-                    ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, ast::Expr::from(it)),
+                    ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
-                        param_name::hints(hints, famous_defs, config, ast::Expr::from(it))
+                        param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it))
                     }
                     ast::Expr::ClosureExpr(it) => {
                         closure_captures::hints(hints, famous_defs, config, it.clone());
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index ec0a4c46c7f..75470778405 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -7,7 +7,7 @@
 use std::iter::zip;
 
 use either::Either;
-use hir::Semantics;
+use hir::{EditionedFileId, Semantics};
 use ide_db::{RootDatabase, famous_defs::FamousDefs};
 
 use stdx::to_lower_snake_case;
@@ -19,6 +19,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
+    file_id: EditionedFileId,
     expr: ast::Expr,
 ) -> Option<()> {
     if !config.parameter_hints {
@@ -39,6 +40,9 @@ pub(super) fn hints(
         .filter_map(|(p, arg)| {
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
+            if range.file_id != file_id {
+                return None;
+            }
             let param_name = p.name(sema.db)?;
             Some((p, param_name, arg, range))
         })
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index aea4ae0fd97..8922a8eb485 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -27,6 +27,27 @@ pub use ide_db::rename::RenameError;
 
 type RenameResult<T> = Result<T, RenameError>;
 
+/// This is similar to `collect::<Result<Vec<_>, _>>`, but unlike it, it succeeds if there is *any* `Ok` item.
+fn ok_if_any<T, E>(iter: impl Iterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
+    let mut err = None;
+    let oks = iter
+        .filter_map(|item| match item {
+            Ok(it) => Some(it),
+            Err(it) => {
+                err = Some(it);
+                None
+            }
+        })
+        .collect::<Vec<_>>();
+    if !oks.is_empty() {
+        Ok(oks)
+    } else if let Some(err) = err {
+        Err(err)
+    } else {
+        Ok(Vec::new())
+    }
+}
+
 /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
 /// being targeted for a rename.
 pub(crate) fn prepare_rename(
@@ -95,58 +116,57 @@ pub(crate) fn rename(
         alias_fallback(syntax, position, &new_name.display(db, edition).to_string());
 
     let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
-        Some(_) => defs
-            // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
-            // properly find "direct" usages/references.
-            .map(|(.., def, new_name, _)| {
-                match kind {
-                    IdentifierKind::Ident => (),
-                    IdentifierKind::Lifetime => {
-                        bail!("Cannot alias reference to a lifetime identifier")
-                    }
-                    IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"),
-                    IdentifierKind::LowercaseSelf => {
-                        bail!("Cannot rename alias reference to `self`")
-                    }
-                };
-                let mut usages = def.usages(&sema).all();
-
-                // FIXME: hack - removes the usage that triggered this rename operation.
-                match usages.references.get_mut(&file_id).and_then(|refs| {
-                    refs.iter()
-                        .position(|ref_| ref_.range.contains_inclusive(position.offset))
-                        .map(|idx| refs.remove(idx))
-                }) {
-                    Some(_) => (),
-                    None => never!(),
-                };
-
-                let mut source_change = SourceChange::default();
-                source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
-                    (
-                        position.file_id,
-                        source_edit_from_references(db, refs, def, &new_name, edition),
-                    )
-                }));
-
-                Ok(source_change)
-            })
-            .collect(),
-        None => defs
-            .map(|(.., def, new_name, rename_def)| {
-                if let Definition::Local(local) = def {
-                    if let Some(self_param) = local.as_self_param(sema.db) {
-                        cov_mark::hit!(rename_self_to_param);
-                        return rename_self_to_param(&sema, local, self_param, &new_name, kind);
-                    }
-                    if kind == IdentifierKind::LowercaseSelf {
-                        cov_mark::hit!(rename_to_self);
-                        return rename_to_self(&sema, local);
-                    }
+        Some(_) => ok_if_any(
+            defs
+                // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
+                // properly find "direct" usages/references.
+                .map(|(.., def, new_name, _)| {
+                    match kind {
+                        IdentifierKind::Ident => (),
+                        IdentifierKind::Lifetime => {
+                            bail!("Cannot alias reference to a lifetime identifier")
+                        }
+                        IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"),
+                        IdentifierKind::LowercaseSelf => {
+                            bail!("Cannot rename alias reference to `self`")
+                        }
+                    };
+                    let mut usages = def.usages(&sema).all();
+
+                    // FIXME: hack - removes the usage that triggered this rename operation.
+                    match usages.references.get_mut(&file_id).and_then(|refs| {
+                        refs.iter()
+                            .position(|ref_| ref_.range.contains_inclusive(position.offset))
+                            .map(|idx| refs.remove(idx))
+                    }) {
+                        Some(_) => (),
+                        None => never!(),
+                    };
+
+                    let mut source_change = SourceChange::default();
+                    source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
+                        (
+                            position.file_id,
+                            source_edit_from_references(db, refs, def, &new_name, edition),
+                        )
+                    }));
+
+                    Ok(source_change)
+                }),
+        ),
+        None => ok_if_any(defs.map(|(.., def, new_name, rename_def)| {
+            if let Definition::Local(local) = def {
+                if let Some(self_param) = local.as_self_param(sema.db) {
+                    cov_mark::hit!(rename_self_to_param);
+                    return rename_self_to_param(&sema, local, self_param, &new_name, kind);
                 }
-                def.rename(&sema, new_name.as_str(), rename_def)
-            })
-            .collect(),
+                if kind == IdentifierKind::LowercaseSelf {
+                    cov_mark::hit!(rename_to_self);
+                    return rename_to_self(&sema, local);
+                }
+            }
+            def.rename(&sema, new_name.as_str(), rename_def)
+        })),
     };
 
     ops?.into_iter()
@@ -320,7 +340,7 @@ fn find_definitions(
             })
         });
 
-    let res: RenameResult<Vec<_>> = symbols.filter_map(Result::transpose).collect();
+    let res: RenameResult<Vec<_>> = ok_if_any(symbols.filter_map(Result::transpose));
     match res {
         Ok(v) => {
             // remove duplicates, comparing `Definition`s
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 5bea74bed7e..203173c11be 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -347,9 +347,7 @@ impl WorkspaceBuildScripts {
                 match message {
                     Message::BuildScriptExecuted(mut message) => {
                         with_output_for(&message.package_id.repr, &mut |name, data| {
-                            progress(format!(
-                                "building compile-time-deps: build script {name} run"
-                            ));
+                            progress(format!("build script {name} run"));
                             let cfgs = {
                                 let mut acc = Vec::new();
                                 for cfg in &message.cfgs {
@@ -380,9 +378,7 @@ impl WorkspaceBuildScripts {
                     }
                     Message::CompilerArtifact(message) => {
                         with_output_for(&message.package_id.repr, &mut |name, data| {
-                            progress(format!(
-                                "building compile-time-deps: proc-macro {name} built"
-                            ));
+                            progress(format!("proc-macro {name} built"));
                             if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
                                 data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
                             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 61c758d5e86..f5932d8cff0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -812,7 +812,7 @@ impl GlobalState {
                 };
 
                 if let Some(state) = state {
-                    self.report_progress("Building build-artifacts", state, msg, None, None);
+                    self.report_progress("Building compile-time-deps", state, msg, None, None);
                 }
             }
             Task::LoadProcMacros(progress) => {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index b50ce644243..160f000387b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -273,28 +273,6 @@ pub trait AttrsOwnerEdit: ast::HasAttrs {
             }
         }
     }
-
-    fn add_attr(&self, attr: ast::Attr) {
-        add_attr(self.syntax(), attr);
-
-        fn add_attr(node: &SyntaxNode, attr: ast::Attr) {
-            let indent = IndentLevel::from_node(node);
-            attr.reindent_to(indent);
-
-            let after_attrs_and_comments = node
-                .children_with_tokens()
-                .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
-                .map_or(Position::first_child_of(node), Position::before);
-
-            ted::insert_all(
-                after_attrs_and_comments,
-                vec![
-                    attr.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n{indent}")).into(),
-                ],
-            )
-        }
-    }
 }
 
 impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index daeb79cf081..9897fd09415 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -190,6 +190,7 @@ fn ty_from_text(text: &str) -> ast::Type {
 }
 
 pub fn ty_alias(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     ident: &str,
     generic_param_list: Option<ast::GenericParamList>,
     type_param_bounds: Option<ast::TypeParam>,
@@ -200,6 +201,7 @@ pub fn ty_alias(
     let assignment_where = assignment_where.flatten();
     quote! {
         TypeAlias {
+            #(#attrs "\n")*
             [type] " "
                 Name { [IDENT ident] }
                 #generic_param_list
@@ -229,6 +231,23 @@ pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
     }
 }
 
+pub fn item_list(body: Option<Vec<ast::Item>>) -> ast::ItemList {
+    let is_break_braces = body.is_some();
+    let body_newline = if is_break_braces { "\n" } else { "" };
+    let body_indent = if is_break_braces { "    " } else { "" };
+
+    let body = match body {
+        Some(bd) => bd.iter().map(|elem| elem.to_string()).join("\n\n    "),
+        None => String::new(),
+    };
+    ast_from_text(&format!("mod C {{{body_newline}{body_indent}{body}{body_newline}}}"))
+}
+
+pub fn mod_(name: ast::Name, body: Option<ast::ItemList>) -> ast::Module {
+    let body = body.map_or(";".to_owned(), |body| format!(" {body}"));
+    ast_from_text(&format!("mod {name}{body}"))
+}
+
 pub fn assoc_item_list(body: Option<Vec<ast::AssocItem>>) -> ast::AssocItemList {
     let is_break_braces = body.is_some();
     let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() };
@@ -277,12 +296,16 @@ fn merge_where_clause(
 }
 
 pub fn impl_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     generic_params: Option<ast::GenericParamList>,
     generic_args: Option<ast::GenericArgList>,
     path_type: ast::Type,
     where_clause: Option<ast::WhereClause>,
     body: Option<ast::AssocItemList>,
 ) -> ast::Impl {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
+
     let gen_args = generic_args.map_or_else(String::new, |it| it.to_string());
 
     let gen_params = generic_params.map_or_else(String::new, |it| it.to_string());
@@ -295,10 +318,11 @@ pub fn impl_(
     };
 
     let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
-    ast_from_text(&format!("impl{gen_params} {path_type}{gen_args}{where_clause}{body}"))
+    ast_from_text(&format!("{attrs}impl{gen_params} {path_type}{gen_args}{where_clause}{body}"))
 }
 
 pub fn impl_trait(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     is_unsafe: bool,
     trait_gen_params: Option<ast::GenericParamList>,
     trait_gen_args: Option<ast::GenericArgList>,
@@ -311,6 +335,8 @@ pub fn impl_trait(
     ty_where_clause: Option<ast::WhereClause>,
     body: Option<ast::AssocItemList>,
 ) -> ast::Impl {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let is_unsafe = if is_unsafe { "unsafe " } else { "" };
 
     let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default();
@@ -334,7 +360,7 @@ pub fn impl_trait(
     let body = body.map_or_else(|| format!("{{{body_newline}}}"), |it| it.to_string());
 
     ast_from_text(&format!(
-        "{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}"
+        "{attrs}{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{body}"
     ))
 }
 
@@ -452,12 +478,18 @@ pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::
     ast_from_text(&format!("use {{{use_trees}}};"))
 }
 
-pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
+pub fn use_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
+    visibility: Option<ast::Visibility>,
+    use_tree: ast::UseTree,
+) -> ast::Use {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{visibility}use {use_tree};"))
+    ast_from_text(&format!("{attrs}{visibility}use {use_tree};"))
 }
 
 pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
@@ -946,16 +978,19 @@ pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
 }
 
 pub fn item_const(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     name: ast::Name,
     ty: ast::Type,
     expr: ast::Expr,
 ) -> ast::Const {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{visibility}const {name}: {ty} = {expr};"))
+    ast_from_text(&format!("{attrs}{visibility}const {name}: {ty} = {expr};"))
 }
 
 pub fn item_static(
@@ -1162,6 +1197,7 @@ pub fn variant(
 }
 
 pub fn fn_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     fn_name: ast::Name,
     type_params: Option<ast::GenericParamList>,
@@ -1174,6 +1210,8 @@ pub fn fn_(
     is_unsafe: bool,
     is_gen: bool,
 ) -> ast::Fn {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let type_params = match type_params {
         Some(type_params) => format!("{type_params}"),
         None => "".into(),
@@ -1197,7 +1235,7 @@ pub fn fn_(
     let gen_literal = if is_gen { "gen " } else { "" };
 
     ast_from_text(&format!(
-        "{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
+        "{attrs}{visibility}{const_literal}{async_literal}{gen_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
     ))
 }
 pub fn struct_(
@@ -1217,12 +1255,15 @@ pub fn struct_(
 }
 
 pub fn enum_(
+    attrs: impl IntoIterator<Item = ast::Attr>,
     visibility: Option<ast::Visibility>,
     enum_name: ast::Name,
     generic_param_list: Option<ast::GenericParamList>,
     where_clause: Option<ast::WhereClause>,
     variant_list: ast::VariantList,
 ) -> ast::Enum {
+    let attrs =
+        attrs.into_iter().fold(String::new(), |mut acc, attr| format_to_acc!(acc, "{}\n", attr));
     let visibility = match visibility {
         None => String::new(),
         Some(it) => format!("{it} "),
@@ -1232,7 +1273,7 @@ pub fn enum_(
     let where_clause = where_clause.map(|it| format!(" {it}")).unwrap_or_default();
 
     ast_from_text(&format!(
-        "{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}"
+        "{attrs}{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}"
     ))
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 738a26fed5d..8bf27f96748 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -2,8 +2,8 @@
 use crate::{
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
     ast::{
-        self, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds,
-        HasVisibility, RangeItem, make,
+        self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
+        HasTypeBounds, HasVisibility, RangeItem, make,
     },
     syntax_editor::SyntaxMappingBuilder,
 };
@@ -107,8 +107,13 @@ impl SyntaxFactory {
         ast
     }
 
-    pub fn use_(&self, visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
-        make::use_(visibility, use_tree).clone_for_update()
+    pub fn use_(
+        &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
+        visibility: Option<ast::Visibility>,
+        use_tree: ast::UseTree,
+    ) -> ast::Use {
+        make::use_(attrs, visibility, use_tree).clone_for_update()
     }
 
     pub fn use_tree(
@@ -840,16 +845,20 @@ impl SyntaxFactory {
 
     pub fn item_const(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         name: ast::Name,
         ty: ast::Type,
         expr: ast::Expr,
     ) -> ast::Const {
-        let ast = make::item_const(visibility.clone(), name.clone(), ty.clone(), expr.clone())
-            .clone_for_update();
+        let (attrs, attrs_input) = iterator_input(attrs);
+        let ast =
+            make::item_const(attrs, visibility.clone(), name.clone(), ty.clone(), expr.clone())
+                .clone_for_update();
 
         if let Some(mut mapping) = self.mappings() {
             let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(attrs_input, ast.attrs().map(|attr| attr.syntax().clone()));
             if let Some(visibility) = visibility {
                 builder.map_node(
                     visibility.syntax().clone(),
@@ -1067,6 +1076,7 @@ impl SyntaxFactory {
 
     pub fn item_enum(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         name: ast::Name,
         generic_param_list: Option<ast::GenericParamList>,
@@ -1074,6 +1084,7 @@ impl SyntaxFactory {
         variant_list: ast::VariantList,
     ) -> ast::Enum {
         let ast = make::enum_(
+            attrs,
             visibility.clone(),
             name.clone(),
             generic_param_list.clone(),
@@ -1182,6 +1193,7 @@ impl SyntaxFactory {
 
     pub fn fn_(
         &self,
+        attrs: impl IntoIterator<Item = ast::Attr>,
         visibility: Option<ast::Visibility>,
         fn_name: ast::Name,
         type_params: Option<ast::GenericParamList>,
@@ -1194,7 +1206,9 @@ impl SyntaxFactory {
         is_unsafe: bool,
         is_gen: bool,
     ) -> ast::Fn {
+        let (attrs, input) = iterator_input(attrs);
         let ast = make::fn_(
+            attrs,
             visibility.clone(),
             fn_name.clone(),
             type_params.clone(),
@@ -1210,6 +1224,7 @@ impl SyntaxFactory {
 
         if let Some(mut mapping) = self.mappings() {
             let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input, ast.attrs().map(|attr| attr.syntax().clone()));
 
             if let Some(visibility) = visibility {
                 builder.map_node(
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index 18f5015e9ea..0b358878fcf 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -619,6 +619,7 @@ mod tests {
     fn test_replace_token_in_parent() {
         let parent_fn = make::fn_(
             None,
+            None,
             make::name("it"),
             None,
             None,
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 534c24be52e..1dc11ee4e4b 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -5588,9 +5588,9 @@
             }
         },
         "node_modules/tmp": {
-            "version": "0.2.3",
-            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
-            "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+            "version": "0.2.4",
+            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz",
+            "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==",
             "dev": true,
             "license": "MIT",
             "engines": {
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index 1fc1da50a0a..f56a0de6163 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "lsp-server"
-version = "0.7.8"
+version = "0.7.9"
 description = "Generic LSP server scaffold."
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server"
@@ -16,9 +16,9 @@ crossbeam-channel.workspace = true
 [dev-dependencies]
 lsp-types = "=0.95"
 ctrlc = "3.4.7"
-anyhow.workspace     = true
+anyhow.workspace = true
 rustc-hash.workspace = true
-toolchain.workspace  = true
+toolchain.workspace = true
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 399d674e41d..305008e69ae 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -84,9 +84,9 @@ pub struct Response {
     // request id. We fail deserialization in that case, so we just
     // make this field mandatory.
     pub id: RequestId,
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(skip_serializing_if = "Option::is_none", default)]
     pub result: Option<serde_json::Value>,
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(skip_serializing_if = "Option::is_none", default)]
     pub error: Option<ResponseError>,
 }
 
@@ -94,7 +94,7 @@ pub struct Response {
 pub struct ResponseError {
     pub code: i32,
     pub message: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(skip_serializing_if = "Option::is_none", default)]
     pub data: Option<serde_json::Value>,
 }
 
@@ -175,7 +175,7 @@ impl Message {
         let msg = match serde_json::from_str(&text) {
             Ok(msg) => msg,
             Err(e) => {
-                return Err(invalid_data!("malformed LSP payload: {:?}", e));
+                return Err(invalid_data!("malformed LSP payload `{e:?}`: {text:?}"));
             }
         };