1use ide_db::imports::merge_imports::try_normalize_import;
2use syntax::{AstNode, ast};
3
4use crate::{
5 AssistId,
6 assist_context::{AssistContext, Assists},
7};
8
9pub(crate) fn normalize_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
21 let use_item = if ctx.has_empty_selection() {
22 ctx.find_node_at_offset()?
23 } else {
24 ctx.covering_element().ancestors().find_map(ast::Use::cast)?
25 };
26
27 let target = use_item.syntax().text_range();
28 let normalized_use_item =
29 try_normalize_import(&use_item, ctx.config.insert_use.granularity.into())?;
30
31 acc.add(AssistId::refactor_rewrite("normalize_import"), "Normalize import", target, |builder| {
32 builder.replace_ast(use_item, normalized_use_item);
33 })
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::tests::{
39 check_assist, check_assist_import_one, check_assist_not_applicable,
40 check_assist_not_applicable_for_import_one,
41 };
42
43 use super::*;
44
45 macro_rules! check_assist_variations {
46 ($fixture: literal, $expected: literal) => {
47 check_assist(
48 normalize_import,
49 concat!("use $0", $fixture, ";"),
50 concat!("use ", $expected, ";"),
51 );
52 check_assist(
53 normalize_import,
54 concat!("$0use ", $fixture, ";"),
55 concat!("use ", $expected, ";"),
56 );
57
58 check_assist_import_one(
59 normalize_import,
60 concat!("use $0", $fixture, ";"),
61 concat!("use {", $expected, "};"),
62 );
63 check_assist_import_one(
64 normalize_import,
65 concat!("$0use ", $fixture, ";"),
66 concat!("use {", $expected, "};"),
67 );
68
69 check_assist_import_one(
70 normalize_import,
71 concat!("use $0{", $fixture, "};"),
72 concat!("use {", $expected, "};"),
73 );
74 check_assist_import_one(
75 normalize_import,
76 concat!("$0use {", $fixture, "};"),
77 concat!("use {", $expected, "};"),
78 );
79
80 check_assist(
81 normalize_import,
82 concat!("use $0", $fixture, "$0;"),
83 concat!("use ", $expected, ";"),
84 );
85 check_assist(
86 normalize_import,
87 concat!("$0use ", $fixture, ";$0"),
88 concat!("use ", $expected, ";"),
89 );
90 };
91 }
92
93 macro_rules! check_assist_not_applicable_variations {
94 ($fixture: literal) => {
95 check_assist_not_applicable(normalize_import, concat!("use $0", $fixture, ";"));
96 check_assist_not_applicable(normalize_import, concat!("$0use ", $fixture, ";"));
97
98 check_assist_not_applicable_for_import_one(
99 normalize_import,
100 concat!("use $0{", $fixture, "};"),
101 );
102 check_assist_not_applicable_for_import_one(
103 normalize_import,
104 concat!("$0use {", $fixture, "};"),
105 );
106 };
107 }
108
109 #[test]
110 fn test_order() {
111 check_assist_variations!(
112 "foo::{*, Qux, bar::{Quux, Bar}, baz, FOO_BAZ, self, Baz, v10, v9, r#aaa}",
113 "foo::{self, Baz, FOO_BAZ, Qux, r#aaa, bar::{Bar, Quux}, baz, v9, v10, *}"
114 );
115 }
116
117 #[test]
118 fn test_braces_kept() {
119 check_assist_not_applicable_variations!("foo::bar::{$0self}");
120
121 check_assist_not_applicable(
125 normalize_import,
126 r"
127mod foo {
128
129 pub mod bar {}
130
131 pub const bar: i32 = 8;
132}
133
134use foo::bar::{$0self};
135
136const bar: u32 = 99;
137
138fn main() {
139 let local_bar = bar;
140}
141
142",
143 );
144 }
145
146 #[test]
147 fn test_redundant_braces() {
148 check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{Qux, baz}");
149 check_assist_variations!("foo::{bar::{self}}", "foo::bar::{self}");
150 check_assist_variations!("foo::{bar::{*}}", "foo::bar::*");
151 check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux");
152 check_assist_variations!(
153 "foo::bar::{{FOO_BAZ, Qux, self}, {*, baz}}",
154 "foo::bar::{self, FOO_BAZ, Qux, baz, *}"
155 );
156 check_assist_variations!(
157 "foo::bar::{{{FOO_BAZ}, {{Qux}, {self}}}, {{*}, {baz}}}",
158 "foo::bar::{self, FOO_BAZ, Qux, baz, *}"
159 );
160 }
161
162 #[test]
163 fn test_merge() {
164 check_assist_variations!(
165 "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux}}",
166 "foo::{FOO_BAZ, Quux, bar::{self, baz, *}, qux, *}"
167 );
168 check_assist_variations!(
169 "foo::{*, bar, {FOO_BAZ, qux}, bar::{*, baz}, {Quux, bar::{baz::Foo}}}",
170 "foo::{FOO_BAZ, Quux, bar::{self, baz::{self, Foo}, *}, qux, *}"
171 );
172 }
173
174 #[test]
175 fn test_merge_self() {
176 check_assist_variations!("std::{fmt, fmt::Display}", "std::fmt::{self, Display}");
177 }
178
179 #[test]
180 fn test_merge_nested() {
181 check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}");
182 }
183
184 #[test]
185 fn test_merge_nested2() {
186 check_assist_variations!("std::{fmt::Debug, fmt::Display}", "std::fmt::{Debug, Display}");
187 }
188
189 #[test]
190 fn test_merge_self_with_nested_self_item() {
191 check_assist_variations!(
192 "std::{fmt::{self, Debug}, fmt::{Write, Display}}",
193 "std::fmt::{self, Debug, Display, Write}"
194 );
195 }
196
197 #[test]
198 fn works_with_trailing_comma() {
199 check_assist(
200 normalize_import,
201 r"
202use $0{
203 foo::bar,
204 foo::baz,
205};
206 ",
207 r"
208use foo::{bar, baz};
209 ",
210 );
211 check_assist_import_one(
212 normalize_import,
213 r"
214use $0{
215 foo::bar,
216 foo::baz,
217};
218",
219 r"
220use {
221 foo::{bar, baz},
222};
223",
224 );
225 }
226
227 #[test]
228 fn not_applicable_to_normalized_import() {
229 check_assist_not_applicable_variations!("foo::bar");
230 check_assist_not_applicable_variations!("foo::bar::*");
231 check_assist_not_applicable_variations!("foo::bar::Qux as Quux");
232 check_assist_not_applicable_variations!("foo::bar::{self, FOO_BAZ, Qux, baz, *}");
233 check_assist_not_applicable_variations!(
234 "foo::{self, Baz, FOO_BAZ, Qux, bar::{Bar, Quux}, baz, *}"
235 );
236 check_assist_not_applicable_variations!(
237 "foo::{FOO_BAZ, Quux, bar::{self, baz, *}, qux, *}"
238 );
239 check_assist_not_applicable_variations!(
240 "foo::{bar::{self, FOO_BAZ, Quux, baz::{self, Foo}, *}, qux, *}"
241 );
242 }
243}