Repository: rust-analyzer/rust-analyzer
Pull request #7889 (2021-03-06 11:11:52)

Make group imports configurable

asv1: Will it be merged?
bors[bot]: :v: asv1 can now approve this pull request. To approve and merge a pull request, simply reply with `bors r+`. More detailed instructions are available [here](https://bors.tech/documentation/getting-started/#reviewing-pull-requests).
lnicola: bors d+

Patch:
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 9ee4b3059b..7656db974f 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -365,14 +365,14 @@ impl Module {
         let _p = profile::span("Module::diagnostics").detail(|| {
             format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
         });
-        let def_map = self.id.def_map(db.upcast());
-        def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
+        let crate_def_map = self.id.def_map(db.upcast());
+        crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
         for decl in self.declarations(db) {
             match decl {
                 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
                 crate::ModuleDef::Module(m) => {
                     // Only add diagnostics from inline modules
-                    if def_map[m.id.local_id].origin.is_inline() {
+                    if crate_def_map[m.id.local_id].origin.is_inline() {
                         m.diagnostics(db, sink)
                     }
                 }
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 16e1bac402..ff4b4a0cf2 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -87,11 +87,11 @@ impl Expander {
         module: ModuleId,
     ) -> Expander {
         let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
-        let def_map = module.def_map(db);
+        let crate_def_map = module.def_map(db);
         let ast_id_map = db.ast_id_map(current_file_id);
         Expander {
             cfg_expander,
-            def_map,
+            def_map: crate_def_map,
             current_file_id,
             ast_id_map,
             module: module.local_id,
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 75c2d756bf..65d85c86a7 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -74,8 +74,8 @@ impl ChildBySource for ImplId {
 
 impl ChildBySource for ModuleId {
     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let def_map = self.def_map(db);
-        let module_data = &def_map[self.local_id];
+        let crate_def_map = self.def_map(db);
+        let module_data = &crate_def_map[self.local_id];
         module_data.scope.child_by_source(db)
     }
 }
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 77ff21739d..e85f85e49e 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -34,7 +34,7 @@ pub struct Resolver {
 // FIXME how to store these best
 #[derive(Debug, Clone)]
 struct ModuleItemMap {
-    def_map: Arc<DefMap>,
+    crate_def_map: Arc<DefMap>,
     module_id: LocalModuleId,
 }
 
@@ -337,11 +337,11 @@ impl Resolver {
         let mut traits = FxHashSet::default();
         for scope in &self.scopes {
             if let Scope::ModuleScope(m) = scope {
-                if let Some(prelude) = m.def_map.prelude() {
+                if let Some(prelude) = m.crate_def_map.prelude() {
                     let prelude_def_map = prelude.def_map(db);
                     traits.extend(prelude_def_map[prelude.local_id].scope.traits());
                 }
-                traits.extend(m.def_map[m.module_id].scope.traits());
+                traits.extend(m.crate_def_map[m.module_id].scope.traits());
             }
         }
         traits
@@ -349,7 +349,7 @@ impl Resolver {
 
     fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> {
         self.scopes.iter().rev().find_map(|scope| match scope {
-            Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
+            Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
 
             _ => None,
         })
@@ -413,21 +413,21 @@ impl Scope {
                 //         def: m.module.into(),
                 //     }),
                 // );
-                m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
+                m.crate_def_map[m.module_id].scope.entries().for_each(|(name, def)| {
                     f(name.clone(), ScopeDef::PerNs(def));
                 });
-                m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
+                m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
                     let scope = PerNs::macros(macro_, Visibility::Public);
                     seen.insert((name.clone(), scope));
                     f(name.clone(), ScopeDef::PerNs(scope));
                 });
-                m.def_map.extern_prelude().for_each(|(name, &def)| {
+                m.crate_def_map.extern_prelude().for_each(|(name, &def)| {
                     f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public)));
                 });
                 BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
                     f(name.clone(), ScopeDef::PerNs(def));
                 });
-                if let Some(prelude) = m.def_map.prelude() {
+                if let Some(prelude) = m.crate_def_map.prelude() {
                     let prelude_def_map = prelude.def_map(db);
                     prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
                         let seen_tuple = (name.clone(), def);
@@ -513,8 +513,8 @@ impl Resolver {
         self.push_scope(Scope::ImplDefScope(impl_def))
     }
 
-    fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
-        self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
+    fn push_module_scope(self, crate_def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
+        self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
     }
 
     fn push_expr_scope(
@@ -534,7 +534,7 @@ impl ModuleItemMap {
         path: &ModPath,
     ) -> Option<ResolveValueResult> {
         let (module_def, idx) =
-            self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
+            self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
         match idx {
             None => {
                 let value = to_value_ns(module_def)?;
@@ -564,7 +564,7 @@ impl ModuleItemMap {
         path: &ModPath,
     ) -> Option<(TypeNs, Option<usize>)> {
         let (module_def, idx) =
-            self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
+            self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
         let res = to_type_ns(module_def)?;
         Some((res, idx))
     }
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index dc38f90e93..1422224ac0 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -99,8 +99,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
             format!("Import `{}`", &import),
             range,
             |builder| {
-                let rewriter =
-                    insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge);
+                let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use);
                 builder.rewrite(rewriter);
             },
         );
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 5c7678b539..4f0422e960 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -154,7 +154,7 @@ fn insert_import(
         mod_path.pop_segment();
         mod_path.push_segment(variant_hir_name.clone());
         let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
-        *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge);
+        *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
     }
     Some(())
 }
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
deleted file mode 100644
index fa12545792..0000000000
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ /dev/null
@@ -1,374 +0,0 @@
-use crate::{
-    assist_context::{AssistContext, Assists},
-    AssistId,
-};
-use ide_db::helpers::FamousDefs;
-use syntax::{
-    ast::{self, Impl, NameOwner},
-    AstNode,
-};
-use test_utils::mark;
-
-// Assist: generate_default_from_new
-//
-// Generates default implementation from new method.
-//
-// ```
-// struct Example { _inner: () }
-//
-// impl Example {
-//     pub fn n$0ew() -> Self {
-//         Self { _inner: () }
-//     }
-// }
-// ```
-// ->
-// ```
-// struct Example { _inner: () }
-//
-// impl Example {
-//     pub fn new() -> Self {
-//         Self { _inner: () }
-//     }
-// }
-//
-// impl Default for Example {
-//     fn default() -> Self {
-//         Self::new()
-//     }
-// }
-// ```
-pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
-    let fn_name = fn_node.name()?;
-
-    if fn_name.text() != "new" {
-        mark::hit!(other_function_than_new);
-        return None;
-    }
-
-    if fn_node.param_list()?.params().next().is_some() {
-        mark::hit!(new_function_with_parameters);
-        return None;
-    }
-
-    let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
-    if is_default_implemented(ctx, &impl_) {
-        mark::hit!(default_block_is_already_present);
-        mark::hit!(struct_in_module_with_default);
-        return None;
-    }
-
-    let insert_location = impl_.syntax().text_range();
-
-    acc.add(
-        AssistId("generate_default_from_new", crate::AssistKind::Generate),
-        "Generate a Default impl from a new fn",
-        insert_location,
-        move |builder| {
-            let code = default_fn_node_for_new(impl_);
-            builder.insert(insert_location.end(), code);
-        },
-    )
-}
-
-fn default_fn_node_for_new(impl_: Impl) -> String {
-    format!(
-        "
-
-impl Default for {} {{
-    fn default() -> Self {{
-        Self::new()
-    }}
-}}",
-        impl_.self_ty().unwrap().syntax().text()
-    )
-}
-
-fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
-    let db = ctx.sema.db;
-    let impl_ = ctx.sema.to_def(impl_);
-    let impl_def = match impl_ {
-        Some(value) => value,
-        None => return false,
-    };
-
-    let ty = impl_def.target_ty(db);
-    let krate = impl_def.module(db).krate();
-    let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
-    let default_trait = match default {
-        Some(value) => value,
-        None => return false,
-    };
-
-    ty.impls_trait(db, default_trait, &[])
-}
-
-#[cfg(test)]
-mod tests {
-    use ide_db::helpers::FamousDefs;
-
-    use crate::tests::{check_assist, check_assist_not_applicable};
-
-    use super::*;
-
-    #[test]
-    fn generate_default() {
-        check_pass(
-            r#"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn ne$0w() -> Self {
-        Self { _inner: () }
-    }
-}
-
-fn main() {}
-"#,
-            r#"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn new() -> Self {
-        Self { _inner: () }
-    }
-}
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-fn main() {}
-"#,
-        );
-    }
-
-    #[test]
-    fn generate_default2() {
-        check_pass(
-            r#"
-struct Test { value: u32 }
-
-impl Test {
-    pub fn ne$0w() -> Self {
-        Self { value: 0 }
-    }
-}
-"#,
-            r#"
-struct Test { value: u32 }
-
-impl Test {
-    pub fn new() -> Self {
-        Self { value: 0 }
-    }
-}
-
-impl Default for Test {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn new_function_with_parameters() {
-        mark::check!(new_function_with_parameters);
-        check_not_applicable(
-            r#"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn $0new(value: ()) -> Self {
-        Self { _inner: value }
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn other_function_than_new() {
-        mark::check!(other_function_than_new);
-        check_not_applicable(
-            r#"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn a$0dd() -> Self {
-        Self { _inner: () }
-    }
-}
-
-"#,
-        );
-    }
-
-    #[test]
-    fn default_block_is_already_present() {
-        mark::check!(default_block_is_already_present);
-        check_not_applicable(
-            r#"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn n$0ew() -> Self {
-        Self { _inner: () }
-    }
-}
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn standalone_new_function() {
-        check_not_applicable(
-            r#"
-fn n$0ew() -> u32 {
-    0
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn multiple_struct_blocks() {
-        check_pass(
-            r#"
-struct Example { _inner: () }
-struct Test { value: u32 }
-
-impl Example {
-    pub fn new$0() -> Self {
-        Self { _inner: () }
-    }
-}
-"#,
-            r#"
-struct Example { _inner: () }
-struct Test { value: u32 }
-
-impl Example {
-    pub fn new() -> Self {
-        Self { _inner: () }
-    }
-}
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn when_struct_is_after_impl() {
-        check_pass(
-            r#"
-impl Example {
-    pub fn $0new() -> Self {
-        Self { _inner: () }
-    }
-}
-
-struct Example { _inner: () }
-"#,
-            r#"
-impl Example {
-    pub fn new() -> Self {
-        Self { _inner: () }
-    }
-}
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-struct Example { _inner: () }
-"#,
-        );
-    }
-
-    #[test]
-    fn struct_in_module() {
-        check_pass(
-            r#"
-mod test {
-    struct Example { _inner: () }
-
-    impl Example {
-        pub fn n$0ew() -> Self {
-            Self { _inner: () }
-        }
-    }
-}
-"#,
-            r#"
-mod test {
-    struct Example { _inner: () }
-
-    impl Example {
-        pub fn new() -> Self {
-            Self { _inner: () }
-        }
-    }
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn struct_in_module_with_default() {
-        mark::check!(struct_in_module_with_default);
-        check_not_applicable(
-            r#"
-mod test {
-    struct Example { _inner: () }
-
-    impl Example {
-        pub fn n$0ew() -> Self {
-            Self { _inner: () }
-        }
-    }
-
-    impl Default for Example {
-        fn default() -> Self {
-            Self::new()
-        }
-    }
-}
-"#,
-        );
-    }
-
-    fn check_pass(before: &str, after: &str) {
-        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
-        check_assist(generate_default_from_new, before, after);
-    }
-
-    fn check_not_applicable(before: &str) {
-        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
-        check_assist_not_applicable(generate_default_from_new, before);
-    }
-}
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 3870b7e75a..9598249812 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -1,7 +1,6 @@
 use hir::HirDisplay;
 use ide_db::{base_db::FileId, helpers::SnippetCap};
 use rustc_hash::{FxHashMap, FxHashSet};
-use stdx::to_lower_snake_case;
 use syntax::{
     ast::{
         self,
@@ -258,15 +257,14 @@ fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
 fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
     match fn_arg {
         ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
-        _ => {
-            let s = fn_arg
+        _ => Some(
+            fn_arg
                 .syntax()
                 .descendants()
                 .filter(|d| ast::NameRef::can_cast(d.kind()))
                 .last()?
-                .to_string();
-            Some(to_lower_snake_case(&s))
-        }
+                .to_string(),
+        ),
     }
 }
 
@@ -449,52 +447,6 @@ mod baz {
         )
     }
 
-    #[test]
-    fn add_function_with_upper_camel_case_arg() {
-        check_assist(
-            generate_function,
-            r"
-struct BazBaz;
-fn foo() {
-    bar$0(BazBaz);
-}
-",
-            r"
-struct BazBaz;
-fn foo() {
-    bar(BazBaz);
-}
-
-fn bar(baz_baz: BazBaz) ${0:-> ()} {
-    todo!()
-}
-",
-        );
-    }
-
-    #[test]
-    fn add_function_with_upper_camel_case_arg_as_cast() {
-        check_assist(
-            generate_function,
-            r"
-struct BazBaz;
-fn foo() {
-    bar$0(&BazBaz as *const BazBaz);
-}
-",
-            r"
-struct BazBaz;
-fn foo() {
-    bar(&BazBaz as *const BazBaz);
-}
-
-fn bar(baz_baz: *const BazBaz) ${0:-> ()} {
-    todo!()
-}
-",
-        );
-    }
-
     #[test]
     fn add_function_with_function_call_arg() {
         check_assist(
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index f3bc6cf398..55481af347 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -44,7 +44,7 @@ pub(crate) fn replace_qualified_name_with_use(
             let mut rewriter = SyntaxRewriter::default();
             shorten_paths(&mut rewriter, syntax.clone(), &path);
             if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
-                rewriter += insert_use(import_scope, path, ctx.config.insert_use.merge);
+                rewriter += insert_use(import_scope, path, ctx.config.insert_use);
                 builder.rewrite(rewriter);
             }
         },
diff --git a/crates/ide_assists/src/handlers/replace_string_with_char.rs b/crates/ide_assists/src/handlers/replace_string_with_char.rs
index 634b9c0b79..317318c247 100644
--- a/crates/ide_assists/src/handlers/replace_string_with_char.rs
+++ b/crates/ide_assists/src/handlers/replace_string_with_char.rs
@@ -25,16 +25,13 @@ pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -
     if value.chars().take(2).count() != 1 {
         return None;
     }
-    let quote_offets = token.quote_offsets()?;
 
     acc.add(
         AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
         "Replace string with char",
         target,
         |edit| {
-            let (left, right) = quote_offets.quotes;
-            edit.replace(left, String::from('\''));
-            edit.replace(right, String::from('\''));
+            edit.replace(token.syntax().text_range(), format!("'{}'", value));
         },
     )
 }
@@ -50,10 +47,10 @@ mod tests {
         check_assist_target(
             replace_string_with_char,
             r#"
-fn f() {
-    let s = "$0c";
-}
-"#,
+            fn f() {
+                let s = "$0c";
+            }
+            "#,
             r#""c""#,
         );
     }
@@ -63,15 +60,15 @@ fn f() {
         check_assist(
             replace_string_with_char,
             r#"
-fn f() {
-    let s = "$0c";
-}
-"#,
+    fn f() {
+        let s = "$0c";
+    }
+    "#,
             r##"
-fn f() {
-    let s = 'c';
-}
-"##,
+    fn f() {
+        let s = 'c';
+    }
+    "##,
         )
     }
 
@@ -80,15 +77,15 @@ fn f() {
         check_assist(
             replace_string_with_char,
             r#"
-fn f() {
-    let s = "$0😀";
-}
-"#,
+    fn f() {
+        let s = "$0😀";
+    }
+    "#,
             r##"
-fn f() {
-    let s = '😀';
-}
-"##,
+    fn f() {
+        let s = '😀';
+    }
+    "##,
         )
     }
 
@@ -97,10 +94,10 @@ fn f() {
         check_assist_not_applicable(
             replace_string_with_char,
             r#"
-fn f() {
-    let s = "$0test";
-}
-"#,
+    fn f() {
+        let s = "$0test";
+    }
+    "#,
         )
     }
 
@@ -109,15 +106,15 @@ fn f() {
         check_assist(
             replace_string_with_char,
             r#"
-fn f() {
-    format!($0"x", 92)
-}
-"#,
+                fn f() {
+                    format!($0"x", 92)
+                }
+                "#,
             r##"
-fn f() {
-    format!('x', 92)
-}
-"##,
+                fn f() {
+                    format!('x', 92)
+                }
+                "##,
         )
     }
 
@@ -126,66 +123,15 @@ fn f() {
         check_assist(
             replace_string_with_char,
             r#"
-fn f() {
-    find($0"x");
-}
-"#,
+                fn f() {
+                    find($0"x");
+                }
+                "#,
             r##"
-fn f() {
-    find('x');
-}
-"##,
-        )
-    }
-
-    #[test]
-    fn replace_string_with_char_newline() {
-        check_assist(
-            replace_string_with_char,
-            r#"
-fn f() {
-    find($0"\n");
-}
-"#,
-            r##"
-fn f() {
-    find('\n');
-}
-"##,
-        )
-    }
-
-    #[test]
-    fn replace_string_with_char_unicode_escape() {
-        check_assist(
-            replace_string_with_char,
-            r#"
-fn f() {
-    find($0"\u{7FFF}");
-}
-"#,
-            r##"
-fn f() {
-    find('\u{7FFF}');
-}
-"##,
-        )
-    }
-
-    #[test]
-    fn replace_raw_string_with_char() {
-        check_assist(
-            replace_string_with_char,
-            r##"
-fn f() {
-    $0r#"X"#
-}
-"##,
-            r##"
-fn f() {
-    'X'
-}
-"##,
+                fn f() {
+                    find('x');
+                }
+                "##,
         )
     }
 }
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index ea62d5f5da..9c8148462c 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -127,7 +127,6 @@ mod handlers {
     mod flip_comma;
     mod flip_trait_bound;
     mod generate_default_from_enum_variant;
-    mod generate_default_from_new;
     mod generate_derive;
     mod generate_enum_is_method;
     mod generate_enum_projection_method;
@@ -190,7 +189,6 @@ mod handlers {
             flip_comma::flip_comma,
             flip_trait_bound::flip_trait_bound,
             generate_default_from_enum_variant::generate_default_from_enum_variant,
-            generate_default_from_new::generate_default_from_new,
             generate_derive::generate_derive,
             generate_enum_is_method::generate_enum_is_method,
             generate_enum_projection_method::generate_enum_as_method,
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 884711f11e..9b2435c4b6 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -5,7 +5,7 @@ use std::fmt;
 use hir::{Documentation, ModPath, Mutability};
 use ide_db::{
     helpers::{
-        insert_use::{self, ImportScope, MergeBehavior},
+        insert_use::{self, ImportScope, InsertUseConfig},
         mod_path_to_ast, SnippetCap,
     },
     SymbolKind,
@@ -280,14 +280,11 @@ pub struct ImportEdit {
 impl ImportEdit {
     /// Attempts to insert the import to the given scope, producing a text edit.
     /// May return no edit in edge cases, such as scope already containing the import.
-    pub fn to_text_edit(&self, merge_behavior: Option<MergeBehavior>) -> Option<TextEdit> {
+    pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
         let _p = profile::span("ImportEdit::to_text_edit");
 
-        let rewriter = insert_use::insert_use(
-            &self.import_scope,
-            mod_path_to_ast(&self.import_path),
-            merge_behavior,
-        );
+        let rewriter =
+            insert_use::insert_use(&self.import_scope, mod_path_to_ast(&self.import_path), cfg);
         let old_ast = rewriter.rewrite_root()?;
         let mut import_insert = TextEdit::builder();
         algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 76f31de9e3..b0b809791e 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -156,7 +156,7 @@ pub fn resolve_completion_edits(
         .find(|mod_path| mod_path.to_string() == full_import_path)?;
 
     ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
-        .to_text_edit(config.insert_use.merge)
+        .to_text_edit(config.insert_use)
         .map(|edit| vec![edit])
 }
 
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index fd40351987..f52aee3445 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -19,6 +19,7 @@ use test_utils::mark;
 pub struct InsertUseConfig {
     pub merge: Option<MergeBehavior>,
     pub prefix_kind: hir::PrefixKind,
+    pub group: bool,
 }
 
 #[derive(Debug, Clone)]
@@ -99,13 +100,13 @@ fn is_inner_comment(token: SyntaxToken) -> bool {
 pub fn insert_use<'a>(
     scope: &ImportScope,
     path: ast::Path,
-    merge: Option<MergeBehavior>,
+    cfg: InsertUseConfig,
 ) -> SyntaxRewriter<'a> {
     let _p = profile::span("insert_use");
     let mut rewriter = SyntaxRewriter::default();
     let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false));
     // merge into existing imports if possible
-    if let Some(mb) = merge {
+    if let Some(mb) = cfg.merge {
         for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
             if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
                 rewriter.replace(existing_use.syntax(), merged.syntax());
@@ -116,7 +117,7 @@ pub fn insert_use<'a>(
 
     // either we weren't allowed to merge or there is no import that fits the merge conditions
     // so look for the place we have to insert to
-    let (insert_position, add_blank) = find_insert_position(scope, path);
+    let (insert_position, add_blank) = find_insert_position(scope, path, cfg.group);
 
     let indent = if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize {
         Some(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into())
@@ -538,6 +539,7 @@ impl AddBlankLine {
 fn find_insert_position(
     scope: &ImportScope,
     insert_path: ast::Path,
+    group_imports: bool,
 ) -> (InsertPosition<SyntaxElement>, AddBlankLine) {
     let group = ImportGroup::new(&insert_path);
     let path_node_iter = scope
@@ -550,6 +552,14 @@ fn find_insert_position(
             let has_tl = tree.use_tree_list().is_some();
             Some((path, has_tl, node))
         });
+
+    if !group_imports {
+        if let Some((_, _, node)) = path_node_iter.last() {
+            return (InsertPosition::After(node.into()), AddBlankLine::Before);
+        }
+        return (InsertPosition::First, AddBlankLine::AfterTwice);
+    }
+
     // Iterator that discards anything thats not in the required grouping
     // This implementation allows the user to rearrange their import groups as this only takes the first group that fits
     let group_iter = path_node_iter
@@ -565,6 +575,7 @@ fn find_insert_position(
             use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater
         },
     );
+
     match post_insert {
         // insert our import before that element
         Some((.., node)) => (InsertPosition::Before(node.into()), AddBlankLine::After),
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index baf10fea93..28a6ee5471 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -138,7 +138,7 @@ impl Expander {
                         parsed_body,
                         false,
                     );
-                    return res.map(|it| it.into_subtree());
+                    return res.map(|it| it.subtree);
                 }
                 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
                     let res = client.run(
@@ -147,7 +147,7 @@ impl Expander {
                         parsed_body,
                         false,
                     );
-                    return res.map(|it| it.into_subtree());
+                    return res.map(|it| it.subtree);
                 }
                 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
                     let res = client.run(
@@ -157,7 +157,7 @@ impl Expander {
                         parsed_body,
                         false,
                     );
-                    return res.map(|it| it.into_subtree());
+                    return res.map(|it| it.subtree);
                 }
                 _ => continue,
             }
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
index b036d4e201..ca6749b9bc 100644
--- a/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/client.rs
@@ -238,7 +238,7 @@ macro_rules! define_client_side {
         $(impl $name {
             #[allow(unused)]
             $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
-                panic!("crates should be linked against the sysroot version of proc_macro, not this one from rust-analyzer");
+                panic!("hello");
                 // Bridge::with(|bridge| {
                 //     let mut b = bridge.cached_buffer.take();
 
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index ceefd187d2..14c853c775 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -25,35 +25,27 @@ type Span = tt::TokenId;
 
 #[derive(Debug, Clone)]
 pub struct TokenStream {
-    pub token_trees: Vec<TokenTree>,
+    pub subtree: tt::Subtree,
 }
 
 impl TokenStream {
     pub fn new() -> Self {
-        TokenStream { token_trees: Default::default() }
+        TokenStream { subtree: Default::default() }
     }
 
     pub fn with_subtree(subtree: tt::Subtree) -> Self {
-        if subtree.delimiter.is_some() {
-            TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
-        } else {
-            TokenStream { token_trees: subtree.token_trees }
-        }
-    }
-
-    pub fn into_subtree(self) -> tt::Subtree {
-        tt::Subtree { delimiter: None, token_trees: self.token_trees }
+        TokenStream { subtree }
     }
 
     pub fn is_empty(&self) -> bool {
-        self.token_trees.is_empty()
+        self.subtree.token_trees.is_empty()
     }
 }
 
 /// Creates a token stream containing a single token tree.
 impl From<TokenTree> for TokenStream {
     fn from(tree: TokenTree) -> TokenStream {
-        TokenStream { token_trees: vec![tree] }
+        TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } }
     }
 }
 
@@ -86,10 +78,10 @@ impl Extend<TokenStream> for TokenStream {
             for tkn in item {
                 match tkn {
                     tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
-                        self.token_trees.extend(subtree.token_trees);
+                        self.subtree.token_trees.extend(subtree.token_trees);
                     }
                     _ => {
-                        self.token_trees.push(tkn);
+                        self.subtree.token_trees.push(tkn);
                     }
                 }
             }
@@ -172,7 +164,7 @@ pub mod token_stream {
         type IntoIter = super::IntoIter<TokenTree>;
 
         fn into_iter(self) -> Self::IntoIter {
-            self.token_trees.into_iter()
+            self.subtree.token_trees.into_iter()
         }
     }
 
@@ -193,22 +185,28 @@ pub mod token_stream {
                 mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?;
 
             let subtree = subtree_replace_token_ids_with_unspecified(subtree);
-            Ok(TokenStream::with_subtree(subtree))
+            Ok(TokenStream { subtree })
         }
     }
 
     impl ToString for TokenStream {
         fn to_string(&self) -> String {
-            return tokentrees_to_text(&self.token_trees[..]);
+            let tt = self.subtree.clone().into();
+            to_text(&tt)
+        }
+    }
 
-            fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
-                tkns.iter()
+    fn to_text(tkn: &tt::TokenTree) -> String {
+        match tkn {
+            tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
+            tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
+            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
+            tt::TokenTree::Subtree(subtree) => {
+                let content = subtree
+                    .token_trees
+                    .iter()
                     .fold((String::new(), true), |(last, last_to_joint), tkn| {
-                        let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
-                            ""
-                        } else {
-                            " "
-                        });
+                        let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " });
                         let mut is_joint = false;
                         if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
                             if punct.spacing == tt::Spacing::Joint {
@@ -217,25 +215,15 @@ pub mod token_stream {
                         }
                         (s, is_joint)
                     })
-                    .0
-            }
-
-            fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
-                match tkn {
-                    tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
-                    tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
-                    tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
-                    tt::TokenTree::Subtree(subtree) => {
-                        let content = tokentrees_to_text(&subtree.token_trees);
-                        let (open, close) = match subtree.delimiter.map(|it| it.kind) {
-                            None => ("", ""),
-                            Some(tt::DelimiterKind::Brace) => ("{", "}"),
-                            Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
-                            Some(tt::DelimiterKind::Bracket) => ("[", "]"),
-                        };
-                        format!("{}{}{}", open, content, close)
-                    }
-                }
+                    .0;
+
+                let (open, close) = match subtree.delimiter.map(|it| it.kind) {
+                    None => ("", ""),
+                    Some(tt::DelimiterKind::Brace) => ("{", "}"),
+                    Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
+                    Some(tt::DelimiterKind::Bracket) => ("[", "]"),
+                };
+                format!("{}{}{}", open, content, close)
             }
         }
     }
@@ -445,7 +433,10 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing {
 
 impl server::Group for Rustc {
     fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group {
-        Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees }
+        Self::Group {
+            delimiter: delim_to_internal(delimiter),
+            token_trees: stream.subtree.token_trees,
+        }
     }
     fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter {
         delim_to_external(group.delimiter)
@@ -453,7 +444,9 @@ impl server::Group for Rustc {
 
     // NOTE: Return value of do not include delimiter
     fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
-        TokenStream { token_trees: group.token_trees.clone() }
+        TokenStream {
+            subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() },
+        }
     }
 
     fn span(&mut self, group: &Self::Group) -> Self::Span {
@@ -762,48 +755,28 @@ mod tests {
     #[test]
     fn test_rustc_server_to_string() {
         let s = TokenStream {
-            token_trees: vec![
-                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                    text: "struct".into(),
-                    id: tt::TokenId::unspecified(),
-                })),
-                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                    text: "T".into(),
-                    id: tt::TokenId::unspecified(),
-                })),
-                tt::TokenTree::Subtree(tt::Subtree {
-                    delimiter: Some(tt::Delimiter {
+            subtree: tt::Subtree {
+                delimiter: None,
+                token_trees: vec![
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                        text: "struct".into(),
+                        id: tt::TokenId::unspecified(),
+                    })),
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                        text: "T".into(),
                         id: tt::TokenId::unspecified(),
-                        kind: tt::DelimiterKind::Brace,
+                    })),
+                    tt::TokenTree::Subtree(tt::Subtree {
+                        delimiter: Some(tt::Delimiter {
+                            id: tt::TokenId::unspecified(),
+                            kind: tt::DelimiterKind::Brace,
+                        }),
+                        token_trees: vec![],
                     }),
-                    token_trees: vec![],
-                }),
-            ],
+                ],
+            },
         };
 
         assert_eq!(s.to_string(), "struct T {}");
     }
-
-    #[test]
-    fn test_rustc_server_from_str() {
-        use std::str::FromStr;
-        let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
-            delimiter: Some(tt::Delimiter {
-                id: tt::TokenId::unspecified(),
-                kind: tt::DelimiterKind::Parenthesis,
-            }),
-            token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                text: "a".into(),
-                id: tt::TokenId::unspecified(),
-            }))],
-        });
-
-        let t1 = TokenStream::from_str("(a)").unwrap();
-        assert_eq!(t1.token_trees.len(), 1);
-        assert_eq!(t1.token_trees[0], subtree_paren_a);
-
-        let t2 = TokenStream::from_str("(a);").unwrap();
-        assert_eq!(t2.token_trees.len(), 2);
-        assert_eq!(t2.token_trees[0], subtree_paren_a);
-    }
 }
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 3bd7e678d3..49994824f5 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -108,7 +108,11 @@ impl BenchCmd {
                         add_call_parenthesis: true,
                         add_call_argument_snippets: true,
                         snippet_cap: SnippetCap::new(true),
-                        insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain },
+                        insert_use: InsertUseConfig {
+                            merge: None,
+                            prefix_kind: PrefixKind::Plain,
+                            group: true,
+                        },
                     };
                     let res = do_work(&mut host, file_id, |analysis| {
                         analysis.completions(&options, file_position)
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3671367025..cac48e9117 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -35,7 +35,8 @@ config_data! {
         assist_importMergeBehaviour: MergeBehaviorDef  = "\"full\"",
         /// The path structure for newly inserted paths to use.
         assist_importPrefix: ImportPrefixDef           = "\"plain\"",
-
+        /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
+        assist_importGroup: bool                       = "true",
         /// Show function name and docs in parameter hints.
         callInfo_full: bool = "true",
 
@@ -574,6 +575,7 @@ impl Config {
                 ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
                 ImportPrefixDef::BySelf => PrefixKind::BySelf,
             },
+            group: self.data.assist_importGroup,
         }
     }
     pub fn completion(&self) -> CompletionConfig {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index c1ca88df67..4235eb6ddf 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1087,7 +1087,11 @@ mod tests {
                     add_call_parenthesis: true,
                     add_call_argument_snippets: true,
                     snippet_cap: SnippetCap::new(true),
-                    insert_use: InsertUseConfig { merge: None, prefix_kind: PrefixKind::Plain },
+                    insert_use: InsertUseConfig {
+                        merge: None,
+                        prefix_kind: PrefixKind::Plain,
+                        group: true,
+                    },
                 },
                 ide_db::base_db::FilePosition { file_id, offset },
             )
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 1dbf2a611d..e564c14279 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -2,6 +2,8 @@
  The strategy to use when inserting new imports or merging imports.
 [[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`)::
  The path structure for newly inserted paths to use.
+[[rust-analyzer.assist.importGroup]]rust-analyzer.assist.importGroup (default: `true`)::
+ Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
 [[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`)::
  Show function name and docs in parameter hints.
 [[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`)::
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 4f22175467..9f28237ff3 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -226,8 +226,6 @@ The are several LSP client implementations for vim or neovim:
    * inlay hints for variables and method chaining, _Neovim Only_
    * semantic highlighting is not implemented yet
 
-Note: for code actions, use `coc-codeaction-cursor` and `coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line` are unlikely to be useful.
-
 ==== LanguageClient-neovim
 
 1. Install LanguageClient-neovim by following the instructions
diff --git a/editors/code/package.json b/editors/code/package.json
index 1987364bc0..5f41f7803a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -385,6 +385,11 @@
                         "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
                     ]
                 },
+                "rust-analyzer.assist.importGroup": {
+                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
+                    "default": true,
+                    "type": "boolean"
+                },
                 "rust-analyzer.callInfo.full": {
                     "markdownDescription": "Show function name and docs in parameter hints.",
                     "default": true,


Test patch:
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index b7f6167607..a7a923beb4 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -23,6 +23,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     insert_use: InsertUseConfig {
         merge: Some(MergeBehavior::Full),
         prefix_kind: hir::PrefixKind::Plain,
+        group: true,
     },
 };
 
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 304b5798f2..4f007aa48b 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -439,37 +439,6 @@ impl Default for Version {
     )
 }
 
-#[test]
-fn doctest_generate_default_from_new() {
-    check_doc_test(
-        "generate_default_from_new",
-        r#####"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn n$0ew() -> Self {
-        Self { _inner: () }
-    }
-}
-"#####,
-        r#####"
-struct Example { _inner: () }
-
-impl Example {
-    pub fn new() -> Self {
-        Self { _inner: () }
-    }
-}
-
-impl Default for Example {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_generate_derive() {
     check_doc_test(
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index baff833051..9da8440310 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -25,6 +25,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     insert_use: InsertUseConfig {
         merge: Some(MergeBehavior::Full),
         prefix_kind: PrefixKind::Plain,
+        group: true,
     },
 };
 
@@ -119,7 +120,7 @@ pub(crate) fn check_edit_with_config(
 
     let mut combined_edit = completion.text_edit().to_owned();
     if let Some(import_text_edit) =
-        completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge))
+        completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use))
     {
         combined_edit.union(import_text_edit).expect(
             "Failed to apply completion resolve changes: change ranges overlap, but should not",
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 4bbe66f1fe..67d0d6fb6d 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -1,7 +1,31 @@
 use super::*;
 
+use hir::PrefixKind;
 use test_utils::assert_eq_text;
 
+#[test]
+fn insert_not_group() {
+    check(
+        "use external_crate2::bar::A",
+        r"
+use std::bar::B;
+use external_crate::bar::A;
+use crate::bar::A;
+use self::bar::A;
+use super::bar::A;",
+        r"
+use std::bar::B;
+use external_crate::bar::A;
+use crate::bar::A;
+use self::bar::A;
+use super::bar::A;
+use external_crate2::bar::A;",
+        None,
+        false,
+        false,
+    );
+}
+
 #[test]
 fn insert_existing() {
     check_full("std::fs", "use std::fs;", "use std::fs;")
@@ -240,6 +264,7 @@ fn insert_empty_module() {
 }",
         None,
         true,
+        true,
     )
 }
 
@@ -584,6 +609,7 @@ fn check(
     ra_fixture_after: &str,
     mb: Option<MergeBehavior>,
     module: bool,
+    group: bool,
 ) {
     let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
     if module {
@@ -597,21 +623,25 @@ fn check(
         .find_map(ast::Path::cast)
         .unwrap();
 
-    let rewriter = insert_use(&file, path, mb);
+    let rewriter = insert_use(
+        &file,
+        path,
+        InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group },
+    );
     let result = rewriter.rewrite(file.as_syntax_node()).to_string();
     assert_eq_text!(ra_fixture_after, &result);
 }
 
 fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Full), false)
+    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Full), false, true)
 }
 
 fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Last), false)
+    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Last), false, true)
 }
 
 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, None, false)
+    check(path, ra_fixture_before, ra_fixture_after, None, false, true)
 }
 
 fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 0484c3af44..22813052df 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -52,7 +52,7 @@ pub fn assert_expand(
     let expander = dylib::Expander::new(&path).unwrap();
     let fixture = parse_string(ra_fixture).unwrap();
 
-    let res = expander.expand(macro_name, &fixture.into_subtree(), None).unwrap();
+    let res = expander.expand(macro_name, &fixture.subtree, None).unwrap();
     assert_eq_text!(&expect.trim(), &format!("{:?}", res));
 }