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

Issue:
"Extract struct from enum variant" drops code comments and attributes of members
The "Extract struct from enum variant" VSCode refactor drops 

- comments
- doc comments
- attributes

Before:

```rust
pub enum Foo {
    Bar,
    Baz {
        // a comment
        /// a doc comment
        #[an_attribute]
        blee: bool
    }
}
```

After:

```rust
pub struct Baz{ pub blee: bool }

pub enum Foo {
    Bar,
    Baz(Baz)
}
```

Pull request description:
Keep comments and attrs when extracting struct from enum variant
Fixes #6730

Still unsure if existing visibilities of fields should be forced to pub (which is what was previously done), or if it's okay to keep it in the extracted struct.

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 498cf7d626..cf3013c080 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,4 @@
 [workspace]
-resolver = "2"
 members = ["xtask/", "lib/*", "crates/*"]
 
 [profile.dev]
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 66f274fa78..8e21783919 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
@@ -151,20 +151,37 @@ fn create_struct_def(
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     visibility: Option<ast::Visibility>,
 ) -> ast::Struct {
-    let pub_vis = Some(make::visibility_pub());
+    let pub_vis = make::visibility_pub();
+
+    let insert_pub = |node: &'_ SyntaxNode| {
+        let pub_vis = pub_vis.clone_for_update();
+        ted::insert(ted::Position::before(node), pub_vis.syntax());
+    };
+
+    // for fields without any existing visibility, use pub visibility
     let field_list = match field_list {
         Either::Left(field_list) => {
-            make::record_field_list(field_list.fields().flat_map(|field| {
-                Some(make::record_field(pub_vis.clone(), field.name()?, field.ty()?))
-            }))
-            .into()
+            let field_list = field_list.clone_for_update();
+
+            field_list
+                .fields()
+                .filter(|field| field.visibility().is_none())
+                .filter_map(|field| field.name())
+                .for_each(|it| insert_pub(it.syntax()));
+
+            field_list.into()
         }
-        Either::Right(field_list) => make::tuple_field_list(
+        Either::Right(field_list) => {
+            let field_list = field_list.clone_for_update();
+
             field_list
                 .fields()
-                .flat_map(|field| Some(make::tuple_field(pub_vis.clone(), field.ty()?))),
-        )
-        .into(),
+                .filter(|field| field.visibility().is_none())
+                .filter_map(|field| field.ty())
+                .for_each(|it| insert_pub(it.syntax()));
+
+            field_list.into()
+        }
     };
 
     make::struct_(visibility, variant_name, None, field_list).clone_for_update()
@@ -290,6 +307,106 @@ enum A { One(One) }"#,
             "enum A { $0One { foo: u32 } }",
             r#"struct One{ pub foo: u32 }
 
+enum A { One(One) }"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_struct_keep_comments_and_attrs_one_field_named() {
+        check_assist(
+            extract_struct_from_enum_variant,
+            r#"
+enum A {
+    $0One {
+        // leading comment
+        /// doc comment
+        #[an_attr]
+        foo: u32
+        // trailing comment
+    }
+}"#,
+            r#"
+struct One{
+        // leading comment
+        /// doc comment
+        #[an_attr]
+        pub foo: u32
+        // trailing comment
+    }
+
+enum A {
+    One(One)
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_struct_keep_comments_and_attrs_several_fields_named() {
+        check_assist(
+            extract_struct_from_enum_variant,
+            r#"
+enum A {
+    $0One {
+        // comment
+        /// doc
+        #[attr]
+        foo: u32,
+        // comment
+        #[attr]
+        /// doc
+        bar: u32
+    }
+}"#,
+            r#"
+struct One{
+        // comment
+        /// doc
+        #[attr]
+        pub foo: u32,
+        // comment
+        #[attr]
+        /// doc
+        pub bar: u32
+    }
+
+enum A {
+    One(One)
+}"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() {
+        check_assist(
+            extract_struct_from_enum_variant,
+            "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }",
+            r#"
+struct One(/* comment */ #[attr] pub u32, /* another */ pub u32 /* tail */);
+
+enum A { One(One) }"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_struct_keep_existing_visibility_named() {
+        check_assist(
+            extract_struct_from_enum_variant,
+            "enum A { $0One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }",
+            r#"
+struct One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, pub d: u32 }
+
+enum A { One(One) }"#,
+        );
+    }
+
+    #[test]
+    fn test_extract_struct_keep_existing_visibility_tuple() {
+        check_assist(
+            extract_struct_from_enum_variant,
+            "enum A { $0One(pub u32, pub(crate) u32, pub(super) u32, u32) }",
+            r#"
+struct One(pub u32, pub(crate) u32, pub(super) u32, pub u32);
+
 enum A { One(One) }"#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index 3cd090737e..add7b8e37a 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -27,14 +27,14 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
     if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) {
         let (merged, to_remove) =
             next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| {
-                try_merge_imports(&use_item, &use_item2, MergeBehavior::Crate).zip(Some(use_item2))
+                try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2))
             })?;
 
         imports = Some((use_item, merged, to_remove));
     } else {
         let (merged, to_remove) =
             next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| {
-                try_merge_trees(&tree, &use_tree, MergeBehavior::Crate).zip(Some(use_tree))
+                try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree))
             })?;
 
         uses = Some((tree.clone(), merged, to_remove))
diff --git a/crates/ide_assists/src/handlers/pull_assignment_up.rs b/crates/ide_assists/src/handlers/pull_assignment_up.rs
index 3128faa68b..28d14b9c3f 100644
--- a/crates/ide_assists/src/handlers/pull_assignment_up.rs
+++ b/crates/ide_assists/src/handlers/pull_assignment_up.rs
@@ -60,12 +60,6 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
         return None;
     };
 
-    if let Some(parent) = tgt.syntax().parent() {
-        if matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) {
-            return None;
-        }
-    }
-
     acc.add(
         AssistId("pull_assignment_up", AssistKind::RefactorExtract),
         "Pull assignment up",
@@ -80,13 +74,7 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
             let tgt = edit.make_ast_mut(tgt);
 
             for (stmt, rhs) in assignments {
-                let mut stmt = stmt.syntax().clone();
-                if let Some(parent) = stmt.parent() {
-                    if ast::ExprStmt::cast(parent.clone()).is_some() {
-                        stmt = parent.clone();
-                    }
-                }
-                ted::replace(stmt, rhs.syntax());
+                ted::replace(stmt.syntax(), rhs.syntax());
             }
             let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone());
             let assign_stmt = make::expr_stmt(assign_expr);
@@ -99,7 +87,7 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
 struct AssignmentsCollector<'a> {
     sema: &'a hir::Semantics<'a, ide_db::RootDatabase>,
     common_lhs: ast::Expr,
-    assignments: Vec<(ast::BinExpr, ast::Expr)>,
+    assignments: Vec<(ast::ExprStmt, ast::Expr)>,
 }
 
 impl<'a> AssignmentsCollector<'a> {
@@ -107,7 +95,6 @@ impl<'a> AssignmentsCollector<'a> {
         for arm in match_expr.match_arm_list()?.arms() {
             match arm.expr()? {
                 ast::Expr::BlockExpr(block) => self.collect_block(&block)?,
-                ast::Expr::BinExpr(expr) => self.collect_expr(&expr)?,
                 _ => return None,
             }
         }
@@ -127,28 +114,22 @@ impl<'a> AssignmentsCollector<'a> {
         }
     }
     fn collect_block(&mut self, block: &ast::BlockExpr) -> Option<()> {
-        let last_expr = block.tail_expr().or_else(|| {
-            if let ast::Stmt::ExprStmt(stmt) = block.statements().last()? {
-                stmt.expr()
-            } else {
-                None
-            }
-        })?;
-
-        if let ast::Expr::BinExpr(expr) = last_expr {
-            return self.collect_expr(&expr);
+        if block.tail_expr().is_some() {
+            return None;
         }
 
-        None
-    }
-
-    fn collect_expr(&mut self, expr: &ast::BinExpr) -> Option<()> {
-        if expr.op_kind()? == ast::BinOp::Assignment
-            && is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs)
-        {
-            self.assignments.push((expr.clone(), expr.rhs()?));
-            return Some(());
+        let last_stmt = block.statements().last()?;
+        if let ast::Stmt::ExprStmt(stmt) = last_stmt {
+            if let ast::Expr::BinExpr(expr) = stmt.expr()? {
+                if expr.op_kind()? == ast::BinOp::Assignment
+                    && is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs)
+                {
+                    self.assignments.push((stmt, expr.rhs()?));
+                    return Some(());
+                }
+            }
         }
+
         None
     }
 }
@@ -260,6 +241,7 @@ fn foo() {
     }
 
     #[test]
+    #[ignore]
     fn test_pull_assignment_up_assignment_expressions() {
         check_assist(
             pull_assignment_up,
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index af2a51a4d7..1482972792 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -9,19 +9,19 @@ use syntax::ast::{
 /// What type of merges are allowed.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum MergeBehavior {
-    /// Merge imports from the same crate into a single use statement.
-    Crate,
-    /// Merge imports from the same module into a single use statement.
-    Module,
+    /// Merge everything together creating deeply nested imports.
+    Full,
+    /// Only merge the last import level, doesn't allow import nesting.
+    Last,
 }
 
 impl MergeBehavior {
     #[inline]
     fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool {
         match self {
-            MergeBehavior::Crate => true,
+            MergeBehavior::Full => true,
             // only simple single segment paths are allowed
-            MergeBehavior::Module => {
+            MergeBehavior::Last => {
                 tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1)
             }
         }
@@ -153,7 +153,7 @@ fn recursive_merge(
                 }
             }
             Err(_)
-                if merge == MergeBehavior::Module
+                if merge == MergeBehavior::Last
                     && use_trees.len() > 0
                     && rhs_t.use_tree_list().is_some() =>
             {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index d83670bdad..8879a9161d 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -36,7 +36,7 @@ config_data! {
     struct ConfigData {
         /// The strategy to use when inserting new imports or merging imports.
         assist_importMergeBehavior |
-        assist_importMergeBehaviour: MergeBehaviorDef  = "\"crate\"",
+        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.
@@ -604,8 +604,8 @@ impl Config {
         InsertUseConfig {
             merge: match self.data.assist_importMergeBehavior {
                 MergeBehaviorDef::None => None,
-                MergeBehaviorDef::Crate => Some(MergeBehavior::Crate),
-                MergeBehaviorDef::Module => Some(MergeBehavior::Module),
+                MergeBehaviorDef::Full => Some(MergeBehavior::Full),
+                MergeBehaviorDef::Last => Some(MergeBehavior::Last),
             },
             prefix_kind: match self.data.assist_importPrefix {
                 ImportPrefixDef::Plain => PrefixKind::Plain,
@@ -709,10 +709,8 @@ enum ManifestOrProjectJson {
 #[serde(rename_all = "snake_case")]
 enum MergeBehaviorDef {
     None,
-    #[serde(alias = "full")]
-    Crate,
-    #[serde(alias = "last")]
-    Module,
+    Full,
+    Last,
 }
 
 #[derive(Deserialize, Debug, Clone)]
@@ -869,11 +867,11 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
         },
         "MergeBehaviorDef" => set! {
             "type": "string",
-            "enum": ["none", "crate", "module"],
+            "enum": ["none", "full", "last"],
             "enumDescriptions": [
-                "Do not merge imports at all.",
-                "Merge imports from the same crate into a single `use` statement.",
-                "Merge imports from the same module into a single `use` statement."
+                "No merging",
+                "Merge all layers of the import trees",
+                "Only merge the last layer of the import trees"
             ],
         },
         "ImportPrefixDef" => set! {
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 56de9681c4..3dcbe397ad 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -133,7 +133,7 @@ fn integrated_completion_benchmark() {
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
             insert_use: InsertUseConfig {
-                merge: Some(MergeBehavior::Crate),
+                merge: Some(MergeBehavior::Full),
                 prefix_kind: hir::PrefixKind::ByCrate,
                 group: true,
             },
@@ -166,7 +166,7 @@ fn integrated_completion_benchmark() {
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
             insert_use: InsertUseConfig {
-                merge: Some(MergeBehavior::Crate),
+                merge: Some(MergeBehavior::Full),
                 prefix_kind: hir::PrefixKind::ByCrate,
                 group: true,
             },
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index f705582007..e28423e993 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -1,4 +1,4 @@
-[[rust-analyzer.assist.importMergeBehavior]]rust-analyzer.assist.importMergeBehavior (default: `"crate"`)::
+[[rust-analyzer.assist.importMergeBehavior]]rust-analyzer.assist.importMergeBehavior (default: `"full"`)::
 +
 --
 The strategy to use when inserting new imports or merging imports.
diff --git a/editors/code/package.json b/editors/code/package.json
index f35d30898f..0cc265aa4f 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -382,17 +382,17 @@
                 "$generated-start": false,
                 "rust-analyzer.assist.importMergeBehavior": {
                     "markdownDescription": "The strategy to use when inserting new imports or merging imports.",
-                    "default": "crate",
+                    "default": "full",
                     "type": "string",
                     "enum": [
                         "none",
-                        "crate",
-                        "module"
+                        "full",
+                        "last"
                     ],
                     "enumDescriptions": [
-                        "Do not merge imports at all.",
-                        "Merge imports from the same crate into a single `use` statement.",
-                        "Merge imports from the same module into a single `use` statement."
+                        "No merging",
+                        "Merge all layers of the import trees",
+                        "Only merge the last layer of the import trees"
                     ]
                 },
                 "rust-analyzer.assist.importPrefix": {


Test patch:
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 0d3969c36d..9c28479984 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -21,7 +21,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     snippet_cap: SnippetCap::new(true),
     allowed: None,
     insert_use: InsertUseConfig {
-        merge: Some(MergeBehavior::Crate),
+        merge: Some(MergeBehavior::Full),
         prefix_kind: hir::PrefixKind::Plain,
         group: true,
     },
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index 939fb2d470..c9857ec5ff 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -20,7 +20,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     add_call_argument_snippets: true,
     snippet_cap: SnippetCap::new(true),
     insert_use: InsertUseConfig {
-        merge: Some(MergeBehavior::Crate),
+        merge: Some(MergeBehavior::Full),
         prefix_kind: PrefixKind::Plain,
         group: true,
     },
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 248227d295..048c213e22 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -44,7 +44,7 @@ fn insert_not_group_empty() {
 
 #[test]
 fn insert_existing() {
-    check_crate("std::fs", "use std::fs;", "use std::fs;")
+    check_full("std::fs", "use std::fs;", "use std::fs;")
 }
 
 #[test]
@@ -249,7 +249,7 @@ use self::fmt;",
 
 #[test]
 fn insert_no_imports() {
-    check_crate(
+    check_full(
         "foo::bar",
         "fn main() {}",
         r"use foo::bar;
@@ -263,7 +263,7 @@ fn insert_empty_file() {
     cov_mark::check!(insert_group_empty_file);
     // empty files will get two trailing newlines
     // this is due to the test case insert_no_imports above
-    check_crate(
+    check_full(
         "foo::bar",
         "",
         r"use foo::bar;
@@ -290,7 +290,7 @@ fn insert_empty_module() {
 #[test]
 fn insert_after_inner_attr() {
     cov_mark::check!(insert_group_empty_inner_attr);
-    check_crate(
+    check_full(
         "foo::bar",
         r"#![allow(unused_imports)]",
         r"#![allow(unused_imports)]
@@ -301,7 +301,7 @@ use foo::bar;",
 
 #[test]
 fn insert_after_inner_attr2() {
-    check_crate(
+    check_full(
         "foo::bar",
         r"#![allow(unused_imports)]
 
@@ -371,12 +371,12 @@ fn main() {}"#,
 
 #[test]
 fn merge_groups() {
-    check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};")
+    check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
 }
 
 #[test]
 fn merge_groups_last() {
-    check_module(
+    check_last(
         "std::io",
         r"use std::fmt::{Result, Display};",
         r"use std::fmt::{Result, Display};
@@ -386,12 +386,12 @@ use std::io;",
 
 #[test]
 fn merge_last_into_self() {
-    check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
+    check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
 }
 
 #[test]
 fn merge_groups_full() {
-    check_crate(
+    check_full(
         "std::io",
         r"use std::fmt::{Result, Display};",
         r"use std::{fmt::{Result, Display}, io};",
@@ -400,21 +400,17 @@ fn merge_groups_full() {
 
 #[test]
 fn merge_groups_long_full() {
-    check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
+    check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
 }
 
 #[test]
 fn merge_groups_long_last() {
-    check_module(
-        "std::foo::bar::Baz",
-        r"use std::foo::bar::Qux;",
-        r"use std::foo::bar::{Baz, Qux};",
-    )
+    check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
 }
 
 #[test]
 fn merge_groups_long_full_list() {
-    check_crate(
+    check_full(
         "std::foo::bar::Baz",
         r"use std::foo::bar::{Qux, Quux};",
         r"use std::foo::bar::{Baz, Quux, Qux};",
@@ -423,7 +419,7 @@ fn merge_groups_long_full_list() {
 
 #[test]
 fn merge_groups_long_last_list() {
-    check_module(
+    check_last(
         "std::foo::bar::Baz",
         r"use std::foo::bar::{Qux, Quux};",
         r"use std::foo::bar::{Baz, Quux, Qux};",
@@ -432,7 +428,7 @@ fn merge_groups_long_last_list() {
 
 #[test]
 fn merge_groups_long_full_nested() {
-    check_crate(
+    check_full(
         "std::foo::bar::Baz",
         r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
         r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
@@ -441,7 +437,7 @@ fn merge_groups_long_full_nested() {
 
 #[test]
 fn merge_groups_long_last_nested() {
-    check_module(
+    check_last(
         "std::foo::bar::Baz",
         r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
         r"use std::foo::bar::Baz;
@@ -451,7 +447,7 @@ use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
 
 #[test]
 fn merge_groups_full_nested_deep() {
-    check_crate(
+    check_full(
         "std::foo::bar::quux::Baz",
         r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
         r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
@@ -460,7 +456,7 @@ fn merge_groups_full_nested_deep() {
 
 #[test]
 fn merge_groups_full_nested_long() {
-    check_crate(
+    check_full(
         "std::foo::bar::Baz",
         r"use std::{foo::bar::Qux};",
         r"use std::{foo::bar::{Baz, Qux}};",
@@ -469,7 +465,7 @@ fn merge_groups_full_nested_long() {
 
 #[test]
 fn merge_groups_last_nested_long() {
-    check_crate(
+    check_full(
         "std::foo::bar::Baz",
         r"use std::{foo::bar::Qux};",
         r"use std::{foo::bar::{Baz, Qux}};",
@@ -478,7 +474,7 @@ fn merge_groups_last_nested_long() {
 
 #[test]
 fn merge_groups_skip_pub() {
-    check_crate(
+    check_full(
         "std::io",
         r"pub use std::fmt::{Result, Display};",
         r"pub use std::fmt::{Result, Display};
@@ -488,7 +484,7 @@ use std::io;",
 
 #[test]
 fn merge_groups_skip_pub_crate() {
-    check_crate(
+    check_full(
         "std::io",
         r"pub(crate) use std::fmt::{Result, Display};",
         r"pub(crate) use std::fmt::{Result, Display};
@@ -498,7 +494,7 @@ use std::io;",
 
 #[test]
 fn merge_groups_skip_attributed() {
-    check_crate(
+    check_full(
         "std::io",
         r#"
 #[cfg(feature = "gated")] use std::fmt::{Result, Display};
@@ -513,7 +509,7 @@ use std::io;
 #[test]
 #[ignore] // FIXME: Support this
 fn split_out_merge() {
-    check_module(
+    check_last(
         "std::fmt::Result",
         r"use std::{fmt, io};",
         r"use std::fmt::{self, Result};
@@ -523,33 +519,29 @@ use std::io;",
 
 #[test]
 fn merge_into_module_import() {
-    check_crate("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
+    check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
 }
 
 #[test]
 fn merge_groups_self() {
-    check_crate("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
+    check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
 }
 
 #[test]
 fn merge_mod_into_glob() {
-    check_crate(
-        "token::TokenKind",
-        r"use token::TokenKind::*;",
-        r"use token::TokenKind::{*, self};",
-    )
+    check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};")
     // FIXME: have it emit `use token::TokenKind::{self, *}`?
 }
 
 #[test]
 fn merge_self_glob() {
-    check_crate("self", r"use self::*;", r"use self::{*, self};")
+    check_full("self", r"use self::*;", r"use self::{*, self};")
     // FIXME: have it emit `use {self, *}`?
 }
 
 #[test]
 fn merge_glob_nested() {
-    check_crate(
+    check_full(
         "foo::bar::quux::Fez",
         r"use foo::bar::{Baz, quux::*};",
         r"use foo::bar::{Baz, quux::{self::*, Fez}};",
@@ -558,7 +550,7 @@ fn merge_glob_nested() {
 
 #[test]
 fn merge_nested_considers_first_segments() {
-    check_crate(
+    check_full(
         "hir_ty::display::write_bounds_like_dyn_trait",
         r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
         r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
@@ -567,7 +559,7 @@ fn merge_nested_considers_first_segments() {
 
 #[test]
 fn skip_merge_last_too_long() {
-    check_module(
+    check_last(
         "foo::bar",
         r"use foo::bar::baz::Qux;",
         r"use foo::bar;
@@ -577,7 +569,7 @@ use foo::bar::baz::Qux;",
 
 #[test]
 fn skip_merge_last_too_long2() {
-    check_module(
+    check_last(
         "foo::bar::baz::Qux",
         r"use foo::bar;",
         r"use foo::bar;
@@ -600,7 +592,7 @@ fn merge_last_fail() {
     check_merge_only_fail(
         r"use foo::bar::{baz::{Qux, Fez}};",
         r"use foo::bar::{baaz::{Quux, Feez}};",
-        MergeBehavior::Module,
+        MergeBehavior::Last,
     );
 }
 
@@ -609,7 +601,7 @@ fn merge_last_fail1() {
     check_merge_only_fail(
         r"use foo::bar::{baz::{Qux, Fez}};",
         r"use foo::bar::baaz::{Quux, Feez};",
-        MergeBehavior::Module,
+        MergeBehavior::Last,
     );
 }
 
@@ -618,7 +610,7 @@ fn merge_last_fail2() {
     check_merge_only_fail(
         r"use foo::bar::baz::{Qux, Fez};",
         r"use foo::bar::{baaz::{Quux, Feez}};",
-        MergeBehavior::Module,
+        MergeBehavior::Last,
     );
 }
 
@@ -627,7 +619,7 @@ fn merge_last_fail3() {
     check_merge_only_fail(
         r"use foo::bar::baz::{Qux, Fez};",
         r"use foo::bar::baaz::{Quux, Feez};",
-        MergeBehavior::Module,
+        MergeBehavior::Last,
     );
 }
 
@@ -656,12 +648,12 @@ fn check(
     assert_eq_text!(ra_fixture_after, &result);
 }
 
-fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Crate), false, true)
+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, true)
 }
 
-fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Module), 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, true)
 }
 
 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {