Unnamed repository; edit this file 'description' to name the repository.
add normalize import assist
davidsemakula 2024-01-28
parent 81d713e · commit a8a18f3
-rw-r--r--crates/ide-assists/src/handlers/normalize_import.rs166
-rw-r--r--crates/ide-assists/src/lib.rs2
-rw-r--r--crates/ide-assists/src/tests/generated.rs13
3 files changed, 181 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/normalize_import.rs b/crates/ide-assists/src/handlers/normalize_import.rs
new file mode 100644
index 0000000000..42076c4ff1
--- /dev/null
+++ b/crates/ide-assists/src/handlers/normalize_import.rs
@@ -0,0 +1,166 @@
+use ide_db::imports::merge_imports::try_normalize_import;
+use syntax::{ast, AstNode};
+
+use crate::{
+ assist_context::{AssistContext, Assists},
+ AssistId, AssistKind,
+};
+
+// Assist: normalize_import
+//
+// Normalizes an import.
+//
+// ```
+// use$0 std::{io, {fmt::Formatter}};
+// ```
+// ->
+// ```
+// use std::{fmt::Formatter, io};
+// ```
+pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let use_item = if ctx.has_empty_selection() {
+ ctx.find_node_at_offset()?
+ } else {
+ ctx.covering_element().ancestors().find_map(ast::Use::cast)?
+ };
+
+ let target = use_item.syntax().text_range();
+ let normalized_use_item =
+ try_normalize_import(&use_item, ctx.config.insert_use.granularity.into())?;
+
+ acc.add(
+ AssistId("normalize_import", AssistKind::RefactorRewrite),
+ "Normalize import",
+ target,
+ |builder| {
+ builder.replace_ast(use_item, normalized_use_item);
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{
+ check_assist, check_assist_import_one, check_assist_not_applicable,
+ check_assist_not_applicable_for_import_one,
+ };
+
+ use super::*;
+
+ macro_rules! check_assist_variations {
+ ($fixture: literal, $expected: literal) => {
+ check_assist(
+ normalize_import,
+ concat!("use $0", $fixture, ";"),
+ concat!("use ", $expected, ";"),
+ );
+ check_assist(
+ normalize_import,
+ concat!("$0use ", $fixture, ";"),
+ concat!("use ", $expected, ";"),
+ );
+
+ check_assist_import_one(
+ normalize_import,
+ concat!("use $0", $fixture, ";"),
+ concat!("use {", $expected, "};"),
+ );
+ check_assist_import_one(
+ normalize_import,
+ concat!("$0use ", $fixture, ";"),
+ concat!("use {", $expected, "};"),
+ );
+
+ check_assist_import_one(
+ normalize_import,
+ concat!("use $0{", $fixture, "};"),
+ concat!("use {", $expected, "};"),
+ );
+ check_assist_import_one(
+ normalize_import,
+ concat!("$0use {", $fixture, "};"),
+ concat!("use {", $expected, "};"),
+ );
+
+ check_assist(
+ normalize_import,
+ concat!("use $0", $fixture, "$0;"),
+ concat!("use ", $expected, ";"),
+ );
+ check_assist(
+ normalize_import,
+ concat!("$0use ", $fixture, ";$0"),
+ concat!("use ", $expected, ";"),
+ );
+ };
+ }
+
+ macro_rules! check_assist_not_applicable_variations {
+ ($fixture: literal) => {
+ check_assist_not_applicable(normalize_import, concat!("use $0", $fixture, ";"));
+ check_assist_not_applicable(normalize_import, concat!("$0use ", $fixture, ";"));
+
+ check_assist_not_applicable_for_import_one(
+ normalize_import,
+ concat!("use $0{", $fixture, "};"),
+ );
+ check_assist_not_applicable_for_import_one(
+ normalize_import,
+ concat!("$0use {", $fixture, "};"),
+ );
+ };
+ }
+
+ #[test]
+ fn test_order() {
+ check_assist_variations!(
+ "foo::{*, Qux, bar::{Quux, Bar}, baz, FOO_BAZ, self, Baz}",
+ "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}"
+ );
+ }
+
+ #[test]
+ fn test_redundant_braces() {
+ check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}");
+ check_assist_variations!("foo::{bar::{self}}", "foo::bar");
+ check_assist_variations!("foo::{bar::{*}}", "foo::bar::*");
+ check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux");
+ check_assist_variations!(
+ "foo::bar::{{FOO_BAZ, Qux, self}, {*, baz}}",
+ "foo::bar::{self, baz, Qux, FOO_BAZ, *}"
+ );
+ check_assist_variations!(
+ "foo::bar::{{{FOO_BAZ}, {{Qux}, {self}}}, {{*}, {baz}}}",
+ "foo::bar::{self, baz, Qux, FOO_BAZ, *}"
+ );
+ }
+
+ #[test]
+ fn test_merge() {
+ check_assist_variations!(
+ "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux}}",
+ "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}"
+ );
+ check_assist_variations!(
+ "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux, bar::{baz::Foo}}}",
+ "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}"
+ );
+ }
+
+ #[test]
+ fn not_applicable_to_normalized_import() {
+ check_assist_not_applicable_variations!("foo::bar");
+ check_assist_not_applicable_variations!("foo::bar::*");
+ check_assist_not_applicable_variations!("foo::bar::Qux as Quux");
+ check_assist_not_applicable_variations!("foo::bar::{self, baz, Qux, FOO_BAZ, *}");
+ check_assist_not_applicable_variations!(
+ "foo::{self, bar::{Bar, Quux}, baz, Baz, Qux, FOO_BAZ, *}"
+ );
+ check_assist_not_applicable_variations!(
+ "foo::{bar::{self, baz, *}, qux, Quux, FOO_BAZ, *}"
+ );
+ check_assist_not_applicable_variations!(
+ "foo::{bar::{self, baz::{self, Foo}, *}, qux, Quux, FOO_BAZ, *}"
+ );
+ }
+}
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index edcf52a9b3..2fec104323 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -183,6 +183,7 @@ mod handlers {
mod move_guard;
mod move_module_to_file;
mod move_to_mod_rs;
+ mod normalize_import;
mod number_representation;
mod promote_local_to_const;
mod pull_assignment_up;
@@ -300,6 +301,7 @@ mod handlers {
move_module_to_file::move_module_to_file,
move_to_mod_rs::move_to_mod_rs,
move_from_mod_rs::move_from_mod_rs,
+ normalize_import::normalize_import,
number_representation::reformat_number_literal,
pull_assignment_up::pull_assignment_up,
promote_local_to_const::promote_local_to_const,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 0ce89ae0a9..8d7c49d52c 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -2218,6 +2218,19 @@ fn t() {}
}
#[test]
+fn doctest_normalize_import() {
+ check_doc_test(
+ "normalize_import",
+ r#####"
+use$0 std::{io, {fmt::Formatter}};
+"#####,
+ r#####"
+use std::{fmt::Formatter, io};
+"#####,
+ )
+}
+
+#[test]
fn doctest_promote_local_to_const() {
check_doc_test(
"promote_local_to_const",