Repository: rust-analyzer/rust-analyzer (rust)

Issue:
code complete cannot select &mut
I click TAB to select "&mut guess",but I got "guess" only . Maybe something goes wrong : 

![cp](https://user-images.githubusercontent.com/4166616/118272440-35f26f80-b4f5-11eb-8a2c-acce30432084.gif)


Pull request description:
fix: Fix code completion not inserting borrow text when client supports InsertAndReplace
bors r+
Fixes #8832

Patch:
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index e76d039b8a..3896be25d8 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -20,7 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast;
 
 use crate::{
-    attr::{Attr, AttrId, AttrInput, Attrs},
+    attr::{AttrId, Attrs},
     builtin_attr,
     db::DefDatabase,
     derive_macro_as_call_id,
@@ -94,16 +94,14 @@ pub(super) fn collect_defs(
         unresolved_imports: Vec::new(),
         resolved_imports: Vec::new(),
 
-        unresolved_macros: Vec::new(),
+        unexpanded_macros: Vec::new(),
         mod_dirs: FxHashMap::default(),
         cfg_options,
         proc_macros,
         exports_proc_macros: false,
         from_glob_import: Default::default(),
-        skip_attrs: Default::default(),
-        derive_helpers_in_scope: Default::default(),
-        registered_attrs: Default::default(),
-        registered_tools: Default::default(),
+        ignore_attrs_on: FxHashSet::default(),
+        derive_helpers_in_scope: FxHashMap::default(),
     };
     match block {
         Some(block) => {
@@ -239,7 +237,7 @@ struct DefCollector<'a> {
     glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
     unresolved_imports: Vec<ImportDirective>,
     resolved_imports: Vec<ImportDirective>,
-    unresolved_macros: Vec<MacroDirective>,
+    unexpanded_macros: Vec<MacroDirective>,
     mod_dirs: FxHashMap<LocalModuleId, ModDir>,
     cfg_options: &'a CfgOptions,
     /// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -249,20 +247,10 @@ struct DefCollector<'a> {
     proc_macros: Vec<(Name, ProcMacroExpander)>,
     exports_proc_macros: bool,
     from_glob_import: PerNsGlobImports,
-    /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
-    /// This map is used to skip all attributes up to and including the one that failed to resolve,
-    /// in order to not expand them twice.
-    ///
-    /// This also stores the attributes to skip when we resolve derive helpers and non-macro
-    /// non-builtin attributes in general.
-    skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
+    ignore_attrs_on: FxHashSet<InFile<ModItem>>,
     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
     /// attributes.
     derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
-    /// Custom attributes registered with `#![register_attr]`.
-    registered_attrs: Vec<String>,
-    /// Custom tool modules registered with `#![register_tool]`.
-    registered_tools: Vec<String>,
 }
 
 impl DefCollector<'_> {
@@ -271,39 +259,11 @@ impl DefCollector<'_> {
         let item_tree = self.db.file_item_tree(file_id.into());
         let module_id = self.def_map.root;
         self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
-
-        let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
-        if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
-            // Process other crate-level attributes.
-            for attr in &*attrs {
-                let attr_name = match attr.path.as_ident() {
-                    Some(name) => name,
-                    None => continue,
-                };
-
-                let registered_name = if *attr_name == hir_expand::name![register_attr]
-                    || *attr_name == hir_expand::name![register_tool]
-                {
-                    match &attr.input {
-                        Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees {
-                            [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
-                            _ => continue,
-                        },
-                        _ => continue,
-                    }
-                } else {
-                    continue;
-                };
-
-                if *attr_name == hir_expand::name![register_attr] {
-                    self.registered_attrs.push(registered_name.to_string());
-                    cov_mark::hit!(register_attr);
-                } else {
-                    self.registered_tools.push(registered_name.to_string());
-                    cov_mark::hit!(register_tool);
-                }
-            }
-
+        if item_tree
+            .top_level_attrs(self.db, self.def_map.krate)
+            .cfg()
+            .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false))
+        {
             ModCollector {
                 def_collector: &mut *self,
                 macro_depth: 0,
@@ -359,7 +319,7 @@ impl DefCollector<'_> {
                 }
             }
 
-            if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
+            if self.reseed_with_unresolved_attributes() == ReachedFixedPoint::Yes {
                 break;
             }
         }
@@ -402,23 +362,27 @@ impl DefCollector<'_> {
     }
 
     /// When the fixed-point loop reaches a stable state, we might still have some unresolved
-    /// attributes (or unexpanded attribute proc macros) left over. This takes one of them, and
-    /// feeds the item it's applied to back into name resolution.
+    /// attributes (or unexpanded attribute proc macros) left over. This takes them, and feeds the
+    /// item they're applied to back into name resolution.
     ///
     /// This effectively ignores the fact that the macro is there and just treats the items as
     /// normal code.
     ///
     /// This improves UX when proc macros are turned off or don't work, and replicates the behavior
     /// before we supported proc. attribute macros.
-    fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
+    fn reseed_with_unresolved_attributes(&mut self) -> ReachedFixedPoint {
         cov_mark::hit!(unresolved_attribute_fallback);
 
-        let mut unresolved_macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
-        let pos = unresolved_macros.iter().position(|directive| {
-            if let MacroDirectiveKind::Attr { ast_id, mod_item, attr } = &directive.kind {
-                self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), *attr);
+        let mut added_items = false;
+        let unexpanded_macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
+        for directive in &unexpanded_macros {
+            if let MacroDirectiveKind::Attr { ast_id, mod_item, .. } = &directive.kind {
+                // Make sure to only add such items once.
+                if !self.ignore_attrs_on.insert(ast_id.ast_id.with_value(*mod_item)) {
+                    continue;
+                }
 
-                let file_id = ast_id.ast_id.file_id;
+                let file_id = self.def_map[directive.module_id].definition_source(self.db).file_id;
                 let item_tree = self.db.file_item_tree(file_id);
                 let mod_dir = self.mod_dirs[&directive.module_id].clone();
                 ModCollector {
@@ -430,20 +394,14 @@ impl DefCollector<'_> {
                     mod_dir,
                 }
                 .collect(&[*mod_item]);
-                true
-            } else {
-                false
+                added_items = true;
             }
-        });
-
-        if let Some(pos) = pos {
-            unresolved_macros.remove(pos);
         }
 
         // The collection above might add new unresolved macros (eg. derives), so merge the lists.
-        self.unresolved_macros.extend(unresolved_macros);
+        self.unexpanded_macros.extend(unexpanded_macros);
 
-        if pos.is_some() {
+        if added_items {
             // Continue name resolution with the new data.
             ReachedFixedPoint::No
         } else {
@@ -915,7 +873,7 @@ impl DefCollector<'_> {
     }
 
     fn resolve_macros(&mut self) -> ReachedFixedPoint {
-        let mut macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
+        let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
         let mut resolved = Vec::new();
         let mut res = ReachedFixedPoint::Yes;
         macros.retain(|directive| {
@@ -964,43 +922,14 @@ impl DefCollector<'_> {
                         Err(UnresolvedMacro { .. }) => (),
                     }
                 }
-                MacroDirectiveKind::Attr { ast_id, mod_item, attr } => {
-                    if let Some(ident) = ast_id.path.as_ident() {
-                        if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id.ast_id) {
-                            if helpers.contains(ident) {
-                                cov_mark::hit!(resolved_derive_helper);
-
-                                // Resolved to derive helper. Collect the item's attributes again,
-                                // starting after the derive helper.
-                                let file_id = ast_id.ast_id.file_id;
-                                let item_tree = self.db.file_item_tree(file_id);
-                                let mod_dir = self.mod_dirs[&directive.module_id].clone();
-                                self.skip_attrs.insert(InFile::new(file_id, *mod_item), *attr);
-                                ModCollector {
-                                    def_collector: &mut *self,
-                                    macro_depth: directive.depth,
-                                    module_id: directive.module_id,
-                                    file_id,
-                                    item_tree: &item_tree,
-                                    mod_dir,
-                                }
-                                .collect(&[*mod_item]);
-
-                                // Remove the original directive since we resolved it.
-                                return false;
-                            }
-                        }
-                    }
-
-                    // Not resolved to a derive helper, so try to resolve as a macro.
-                    // FIXME: not yet :)
+                MacroDirectiveKind::Attr { .. } => {
+                    // not yet :)
                 }
             }
 
             true
         });
-        // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
-        self.unresolved_macros.extend(macros);
+        self.unexpanded_macros = macros;
 
         for (module_id, macro_call_id, depth) in resolved {
             self.collect_macro_expansion(module_id, macro_call_id, depth);
@@ -1071,7 +1000,7 @@ impl DefCollector<'_> {
     fn finish(mut self) -> DefMap {
         // Emit diagnostics for all remaining unexpanded macros.
 
-        for directive in &self.unresolved_macros {
+        for directive in &self.unexpanded_macros {
             match &directive.kind {
                 MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id(
                     ast_id,
@@ -1173,7 +1102,7 @@ impl ModCollector<'_, '_> {
 
         // Prelude module is always considered to be `#[macro_use]`.
         if let Some(prelude_module) = self.def_collector.def_map.prelude {
-            if prelude_module.krate != krate {
+            if prelude_module.krate != self.def_collector.def_map.krate {
                 cov_mark::hit!(prelude_is_macro_use);
                 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
             }
@@ -1274,6 +1203,11 @@ impl ModCollector<'_, '_> {
                 ModItem::Struct(id) => {
                     let it = &self.item_tree[id];
 
+                    // FIXME: check attrs to see if this is an attribute macro invocation;
+                    // in which case we don't add the invocation, just a single attribute
+                    // macro invocation
+                    self.collect_derives(&attrs, it.ast_id.upcast());
+
                     def = Some(DefData {
                         id: StructLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
                             .intern(self.def_collector.db)
@@ -1286,6 +1220,11 @@ impl ModCollector<'_, '_> {
                 ModItem::Union(id) => {
                     let it = &self.item_tree[id];
 
+                    // FIXME: check attrs to see if this is an attribute macro invocation;
+                    // in which case we don't add the invocation, just a single attribute
+                    // macro invocation
+                    self.collect_derives(&attrs, it.ast_id.upcast());
+
                     def = Some(DefData {
                         id: UnionLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
                             .intern(self.def_collector.db)
@@ -1298,6 +1237,11 @@ impl ModCollector<'_, '_> {
                 ModItem::Enum(id) => {
                     let it = &self.item_tree[id];
 
+                    // FIXME: check attrs to see if this is an attribute macro invocation;
+                    // in which case we don't add the invocation, just a single attribute
+                    // macro invocation
+                    self.collect_derives(&attrs, it.ast_id.upcast());
+
                     def = Some(DefData {
                         id: EnumLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
                             .intern(self.def_collector.db)
@@ -1509,103 +1453,76 @@ impl ModCollector<'_, '_> {
     ///
     /// Returns `Err` when some attributes could not be resolved to builtins and have been
     /// registered as unresolved.
-    ///
-    /// If `ignore_up_to` is `Some`, attributes precending and including that attribute will be
-    /// assumed to be resolved already.
     fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
-        let mut ignore_up_to =
-            self.def_collector.skip_attrs.get(&InFile::new(self.file_id, mod_item)).copied();
-        for attr in attrs.iter().skip_while(|attr| match ignore_up_to {
-            Some(id) if attr.id == id => {
-                ignore_up_to = None;
-                true
+        fn is_builtin_attr(path: &ModPath) -> bool {
+            if path.kind == PathKind::Plain {
+                if let Some(tool_module) = path.segments().first() {
+                    let tool_module = tool_module.to_string();
+                    if builtin_attr::TOOL_MODULES.iter().any(|m| tool_module == *m) {
+                        return true;
+                    }
+                }
+
+                if let Some(name) = path.as_ident() {
+                    let name = name.to_string();
+                    if builtin_attr::INERT_ATTRIBUTES
+                        .iter()
+                        .chain(builtin_attr::EXTRA_ATTRIBUTES)
+                        .any(|attr| name == *attr)
+                    {
+                        return true;
+                    }
+                }
             }
-            Some(_) => true,
-            None => false,
-        }) {
-            if attr.path.as_ident() == Some(&hir_expand::name![derive]) {
-                self.collect_derive(attr, mod_item);
-            } else if self.is_builtin_or_registered_attr(&attr.path) {
-                continue;
-            } else {
-                log::debug!("non-builtin attribute {}", attr.path);
+
+            false
+        }
+
+        // We failed to resolve an attribute on this item earlier, and are falling back to treating
+        // the item as-is.
+        if self.def_collector.ignore_attrs_on.contains(&InFile::new(self.file_id, mod_item)) {
+            return Ok(());
+        }
+
+        match attrs.iter().find(|attr| !is_builtin_attr(&attr.path)) {
+            Some(non_builtin_attr) => {
+                log::debug!("non-builtin attribute {}", non_builtin_attr.path);
 
                 let ast_id = AstIdWithPath::new(
                     self.file_id,
                     mod_item.ast_id(self.item_tree),
-                    attr.path.as_ref().clone(),
+                    non_builtin_attr.path.as_ref().clone(),
                 );
-                self.def_collector.unresolved_macros.push(MacroDirective {
+                self.def_collector.unexpanded_macros.push(MacroDirective {
                     module_id: self.module_id,
                     depth: self.macro_depth + 1,
-                    kind: MacroDirectiveKind::Attr { ast_id, attr: attr.id, mod_item },
+                    kind: MacroDirectiveKind::Attr { ast_id, attr: non_builtin_attr.id, mod_item },
                 });
 
-                return Err(());
+                Err(())
             }
+            None => Ok(()),
         }
-
-        Ok(())
     }
 
-    fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
-        if path.kind == PathKind::Plain {
-            if let Some(tool_module) = path.segments().first() {
-                let tool_module = tool_module.to_string();
-                if builtin_attr::TOOL_MODULES
-                    .iter()
-                    .copied()
-                    .chain(self.def_collector.registered_tools.iter().map(|s| &**s))
-                    .any(|m| tool_module == *m)
-                {
-                    return true;
-                }
-            }
-
-            if let Some(name) = path.as_ident() {
-                let name = name.to_string();
-                if builtin_attr::INERT_ATTRIBUTES
-                    .iter()
-                    .chain(builtin_attr::EXTRA_ATTRIBUTES)
-                    .copied()
-                    .chain(self.def_collector.registered_attrs.iter().map(|s| &**s))
-                    .any(|attr| name == *attr)
-                {
-                    return true;
+    fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
+        for derive in attrs.by_key("derive").attrs() {
+            match derive.parse_derive() {
+                Some(derive_macros) => {
+                    for path in derive_macros {
+                        let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
+                        self.def_collector.unexpanded_macros.push(MacroDirective {
+                            module_id: self.module_id,
+                            depth: self.macro_depth + 1,
+                            kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
+                        });
+                    }
                 }
-            }
-        }
-
-        false
-    }
-
-    fn collect_derive(&mut self, attr: &Attr, mod_item: ModItem) {
-        let ast_id: FileAstId<ast::Item> = match mod_item {
-            ModItem::Struct(it) => self.item_tree[it].ast_id.upcast(),
-            ModItem::Union(it) => self.item_tree[it].ast_id.upcast(),
-            ModItem::Enum(it) => self.item_tree[it].ast_id.upcast(),
-            _ => {
-                // Cannot use derive on this item.
-                // FIXME: diagnose
-                return;
-            }
-        };
-
-        match attr.parse_derive() {
-            Some(derive_macros) => {
-                for path in derive_macros {
-                    let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
-                    self.def_collector.unresolved_macros.push(MacroDirective {
-                        module_id: self.module_id,
-                        depth: self.macro_depth + 1,
-                        kind: MacroDirectiveKind::Derive { ast_id, derive_attr: attr.id },
-                    });
+                None => {
+                    // FIXME: diagnose
+                    log::debug!("malformed derive: {:?}", derive);
                 }
             }
-            None => {
-                // FIXME: diagnose
-                log::debug!("malformed derive: {:?}", attr);
-            }
         }
     }
 
@@ -1769,7 +1686,7 @@ impl ModCollector<'_, '_> {
             ast_id.path.kind = PathKind::Super(0);
         }
 
-        self.def_collector.unresolved_macros.push(MacroDirective {
+        self.def_collector.unexpanded_macros.push(MacroDirective {
             module_id: self.module_id,
             depth: self.macro_depth + 1,
             kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment },
@@ -1814,16 +1731,14 @@ mod tests {
             glob_imports: FxHashMap::default(),
             unresolved_imports: Vec::new(),
             resolved_imports: Vec::new(),
-            unresolved_macros: Vec::new(),
+            unexpanded_macros: Vec::new(),
             mod_dirs: FxHashMap::default(),
             cfg_options: &CfgOptions::default(),
             proc_macros: Default::default(),
             exports_proc_macros: false,
             from_glob_import: Default::default(),
-            skip_attrs: Default::default(),
-            derive_helpers_in_scope: Default::default(),
-            registered_attrs: Default::default(),
-            registered_tools: Default::default(),
+            ignore_attrs_on: FxHashSet::default(),
+            derive_helpers_in_scope: FxHashMap::default(),
         };
         collector.seed_with_top_level();
         collector.collect();
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index ef67ea2e99..5a5dc9afdb 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -164,8 +164,6 @@ pub mod known {
         doc,
         cfg,
         cfg_attr,
-        register_attr,
-        register_tool,
         // Components of known path (value or mod name)
         std,
         core,
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index d4748ef3a0..dda5a6631c 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -33,19 +33,20 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 // use super::AssistContext;
 // ```
 //
-// .Import Granularity
+// .Merge Behavior
 //
-// It is possible to configure how use-trees are merged with the `importGranularity` setting.
+// It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
 // It has the following configurations:
 //
-// - `crate`: Merge imports from the same crate into a single use statement. This kind of
+// - `full`: This setting will cause auto-import to always completely merge use-trees that share the
+//  same path prefix while also merging inner trees that share the same path-prefix. This kind of
 //  nesting is only supported in Rust versions later than 1.24.
-// - `module`: Merge imports from the same module into a single use statement.
-// - `item`: Don't merge imports at all, creating one import per item.
-// - `preserve`: Do not change the granularity of any imports. For auto-import this has the same
-//  effect as `item`.
+// - `last`: This setting will cause auto-import to merge use-trees as long as the resulting tree
+//  will only contain a nesting of single segment paths at the very end.
+// - `none`: This setting will cause auto-import to never merge use-trees keeping them as simple
+//  paths.
 //
-// In `VS Code` the configuration for this is `rust-analyzer.assist.importGranularity`.
+// In `VS Code` the configuration for this is `rust-analyzer.assist.importMergeBehavior`.
 //
 // .Import Prefix
 //
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index fc117bd9a8..31854840c2 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -212,20 +212,6 @@ pub(crate) use std::fmt::{Debug, Display};
         )
     }
 
-    #[test]
-    fn merge_pub_in_path_crate() {
-        check_assist(
-            merge_imports,
-            r"
-pub(in this::path) use std::fmt$0::Debug;
-pub(in this::path) use std::fmt::Display;
-",
-            r"
-pub(in this::path) use std::fmt::{Debug, Display};
-",
-        )
-    }
-
     #[test]
     fn test_merge_nested() {
         check_assist(
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index 0dbabb44fb..697e8bcffa 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -292,7 +292,9 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
 pub fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
     match (vis0, vis1) {
         (None, None) => true,
-        (Some(vis0), Some(vis1)) => vis0.is_eq_to(&vis1),
+        // FIXME: Don't use the string representation to check for equality
+        // spaces inside of the node would break this comparison
+        (Some(vis0), Some(vis1)) => vis0.to_string() == vis1.to_string(),
         _ => false,
     }
 }
@@ -301,14 +303,9 @@ pub fn eq_attrs(
     attrs0: impl Iterator<Item = ast::Attr>,
     attrs1: impl Iterator<Item = ast::Attr>,
 ) -> bool {
-    // FIXME order of attributes should not matter
-    let attrs0 = attrs0
-        .flat_map(|attr| attr.syntax().descendants_with_tokens())
-        .flat_map(|it| it.into_token());
-    let attrs1 = attrs1
-        .flat_map(|attr| attr.syntax().descendants_with_tokens())
-        .flat_map(|it| it.into_token());
-    stdx::iter_eq_by(attrs0, attrs1, |tok, tok2| tok.text() == tok2.text())
+    let attrs0 = attrs0.map(|attr| attr.to_string());
+    let attrs1 = attrs1.map(|attr| attr.to_string());
+    attrs0.eq(attrs1)
 }
 
 fn path_is_self(path: &ast::Path) -> bool {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index ef9e0aee9b..0a3a56773d 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -270,9 +270,12 @@ pub(crate) fn completion_item(
             set_score(&mut lsp_item_with_ref, relevance);
             lsp_item_with_ref.label =
                 format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
-            if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit
-            {
-                it.new_text = format!("&{}{}", mutability.as_keyword_for_ref(), it.new_text);
+            if let Some(it) = &mut lsp_item_with_ref.text_edit {
+                let new_text = match it {
+                    lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
+                    lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
+                };
+                *new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
             }
             vec![lsp_item_with_ref, lsp_item]
         }
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 18d5fadb9c..340fcacfa3 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -140,34 +140,6 @@ impl JodChild {
     }
 }
 
-// feature: iter_order_by
-// Iterator::eq_by
-pub fn iter_eq_by<I, I2, F>(this: I2, other: I, mut eq: F) -> bool
-where
-    I: IntoIterator,
-    I2: IntoIterator,
-    F: FnMut(I2::Item, I::Item) -> bool,
-{
-    let mut other = other.into_iter();
-    let mut this = this.into_iter();
-
-    loop {
-        let x = match this.next() {
-            None => return other.next().is_none(),
-            Some(val) => val,
-        };
-
-        let y = match other.next() {
-            None => return false,
-            Some(val) => val,
-        };
-
-        if !eq(x, y) {
-            return false;
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index df8f98b5b5..bef49238f5 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -608,29 +608,6 @@ impl ast::Visibility {
             None => VisibilityKind::Pub,
         }
     }
-
-    pub fn is_eq_to(&self, other: &Self) -> bool {
-        match (self.kind(), other.kind()) {
-            (VisibilityKind::In(this), VisibilityKind::In(other)) => {
-                stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
-                    lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
-                        (PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
-                        | (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
-                        | (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
-                        (PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
-                            lhs.text() == rhs.text()
-                        }
-                        _ => false,
-                    })
-                })
-            }
-            (VisibilityKind::PubSelf, VisibilityKind::PubSelf)
-            | (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
-            | (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
-            | (VisibilityKind::Pub, VisibilityKind::Pub) => true,
-            _ => false,
-        }
-    }
 }
 
 impl ast::LifetimeParam {
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 1d8a1930a9..f96c09a79f 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -276,7 +276,7 @@ nvim_lsp.rust_analyzer.setup({
     settings = {
         ["rust-analyzer"] = {
             assist = {
-                importGranularity = "module",
+                importMergeBehavior = "last",
                 importPrefix = "by_self",
             },
             cargo = {


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 75147d973a..543975e075 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -237,20 +237,3 @@ fn good_out_dir_diagnostic() {
         "#,
     );
 }
-
-#[test]
-fn register_attr_and_tool() {
-    cov_mark::check!(register_attr);
-    cov_mark::check!(register_tool);
-    check_no_diagnostics(
-        r#"
-#![register_tool(tool)]
-#![register_attr(attr)]
-
-#[tool::path]
-#[attr]
-struct S;
-        "#,
-    );
-    // NB: we don't currently emit diagnostics here
-}
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 04de107f5b..6eb5f97be1 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -735,28 +735,6 @@ fn unresolved_attributes_fall_back_track_per_file_moditems() {
     );
 }
 
-#[test]
-fn resolves_derive_helper() {
-    cov_mark::check!(resolved_derive_helper);
-    check(
-        r#"
-//- /main.rs crate:main deps:proc
-#[derive(proc::Derive)]
-#[helper]
-#[unresolved]
-struct S;
-
-//- /proc.rs crate:proc
-#[proc_macro_derive(Derive, attributes(helper))]
-fn derive() {}
-        "#,
-        expect![[r#"
-            crate
-            S: t v
-        "#]],
-    )
-}
-
 #[test]
 fn macro_expansion_overflow() {
     cov_mark::check!(macro_expansion_overflow);