rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

220 lines
6.4 KiB
Rust
Raw Normal View History

2024-01-20 16:49:16 +00:00
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 test_merge_self() {
check_assist_variations!("std::{fmt, fmt::Display}", "std::fmt::{self, Display}");
}
#[test]
fn test_merge_nested() {
check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}");
}
#[test]
fn test_merge_nested2() {
check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}");
}
#[test]
fn test_merge_self_with_nested_self_item() {
check_assist_variations!(
"std::{fmt::{self, Debug}, fmt::{Write, Display}}",
"std::fmt::{self, Debug, Display, Write}"
);
}
#[test]
fn works_with_trailing_comma() {
check_assist(
normalize_import,
r"
use $0{
foo::bar,
foo::baz,
};
",
r"
use foo::{bar, baz};
",
);
check_assist_import_one(
normalize_import,
r"
use $0{
foo::bar,
foo::baz,
};
",
r"
use {
foo::{bar, baz},
};
",
);
}
2024-01-20 16:49:16 +00:00
#[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, *}"
);
}
}