diff options
author | unexge <[email protected]> | 2020-08-12 22:51:15 +0100 |
---|---|---|
committer | unexge <[email protected]> | 2020-08-20 19:34:53 +0100 |
commit | 128eef779f572a8120cb475d86a373ac4c9e5559 (patch) | |
tree | b7ef226cde7c59c0a6869b68519b814d3ead6f56 /crates/assists/src | |
parent | 71d2c4a0278c2200a88dad40de94681a1e9768fc (diff) |
Improve AST replacing in expand glob import
Diffstat (limited to 'crates/assists/src')
-rw-r--r-- | crates/assists/src/handlers/expand_glob_import.rs | 267 |
1 files changed, 229 insertions, 38 deletions
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs index 81d0af2f3..0288d1c77 100644 --- a/crates/assists/src/handlers/expand_glob_import.rs +++ b/crates/assists/src/handlers/expand_glob_import.rs | |||
@@ -4,7 +4,7 @@ use ide_db::{ | |||
4 | defs::{classify_name_ref, Definition, NameRefClass}, | 4 | defs::{classify_name_ref, Definition, NameRefClass}, |
5 | RootDatabase, | 5 | RootDatabase, |
6 | }; | 6 | }; |
7 | use syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; | 7 | use syntax::{ast, AstNode, SyntaxToken, T}; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | assist_context::{AssistBuilder, AssistContext, Assists}, | 10 | assist_context::{AssistBuilder, AssistContext, Assists}, |
@@ -38,7 +38,7 @@ use crate::{ | |||
38 | // ``` | 38 | // ``` |
39 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
40 | let star = ctx.find_token_at_offset(T![*])?; | 40 | let star = ctx.find_token_at_offset(T![*])?; |
41 | let mod_path = find_mod_path(&star)?; | 41 | let (parent, mod_path) = find_parent_and_path(&star)?; |
42 | let module = match ctx.sema.resolve_path(&mod_path)? { | 42 | let module = match ctx.sema.resolve_path(&mod_path)? { |
43 | PathResolution::Def(ModuleDef::Module(it)) => it, | 43 | PathResolution::Def(ModuleDef::Module(it)) => it, |
44 | _ => return None, | 44 | _ => return None, |
@@ -52,19 +52,23 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
52 | source_file.syntax().descendants().filter_map(ast::NameRef::cast).collect(); | 52 | source_file.syntax().descendants().filter_map(ast::NameRef::cast).collect(); |
53 | let used_names = find_used_names(ctx, defs_in_mod, name_refs_in_source_file); | 53 | let used_names = find_used_names(ctx, defs_in_mod, name_refs_in_source_file); |
54 | 54 | ||
55 | let parent = star.parent().parent()?; | 55 | let target = parent.syntax(); |
56 | acc.add( | 56 | acc.add( |
57 | AssistId("expand_glob_import", AssistKind::RefactorRewrite), | 57 | AssistId("expand_glob_import", AssistKind::RefactorRewrite), |
58 | "Expand glob import", | 58 | "Expand glob import", |
59 | parent.text_range(), | 59 | target.text_range(), |
60 | |builder| { | 60 | |builder| { |
61 | replace_ast(builder, &parent, mod_path, used_names); | 61 | replace_ast(builder, parent, mod_path, used_names); |
62 | }, | 62 | }, |
63 | ) | 63 | ) |
64 | } | 64 | } |
65 | 65 | ||
66 | fn find_mod_path(star: &SyntaxToken) -> Option<ast::Path> { | 66 | fn find_parent_and_path(star: &SyntaxToken) -> Option<(ast::UseTree, ast::Path)> { |
67 | star.ancestors().find_map(|n| ast::UseTree::cast(n).and_then(|u| u.path())) | 67 | star.ancestors().find_map(|n| { |
68 | let use_tree = ast::UseTree::cast(n)?; | ||
69 | let path = use_tree.path()?; | ||
70 | Some((use_tree, path)) | ||
71 | }) | ||
68 | } | 72 | } |
69 | 73 | ||
70 | #[derive(PartialEq)] | 74 | #[derive(PartialEq)] |
@@ -137,41 +141,28 @@ fn find_used_names( | |||
137 | 141 | ||
138 | fn replace_ast( | 142 | fn replace_ast( |
139 | builder: &mut AssistBuilder, | 143 | builder: &mut AssistBuilder, |
140 | node: &SyntaxNode, | 144 | parent: ast::UseTree, |
141 | path: ast::Path, | 145 | path: ast::Path, |
142 | used_names: Vec<Name>, | 146 | used_names: Vec<Name>, |
143 | ) { | 147 | ) { |
144 | let replacement: Either<ast::UseTree, ast::UseTreeList> = match used_names.as_slice() { | 148 | let replacement = match used_names.as_slice() { |
145 | [name] => Either::Left(ast::make::use_tree( | 149 | [name] => ast::make::use_tree( |
146 | ast::make::path_from_text(&format!("{}::{}", path, name)), | 150 | ast::make::path_from_text(&format!("{}::{}", path, name)), |
147 | None, | 151 | None, |
148 | None, | 152 | None, |
149 | false, | 153 | false, |
150 | )), | 154 | ), |
151 | names => Either::Right(ast::make::use_tree_list(names.iter().map(|n| { | 155 | names => ast::make::use_tree( |
152 | ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false) | 156 | path, |
153 | }))), | 157 | Some(ast::make::use_tree_list(names.iter().map(|n| { |
154 | }; | 158 | ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false) |
155 | 159 | }))), | |
156 | let mut replace_node = |replacement: Either<ast::UseTree, ast::UseTreeList>| { | 160 | None, |
157 | algo::diff(node, &replacement.either(|u| u.syntax().clone(), |ut| ut.syntax().clone())) | 161 | false, |
158 | .into_text_edit(builder.text_edit_builder()); | 162 | ), |
159 | }; | 163 | }; |
160 | 164 | ||
161 | match_ast! { | 165 | builder.replace_ast(parent, replacement); |
162 | match node { | ||
163 | ast::UseTree(use_tree) => { | ||
164 | replace_node(replacement); | ||
165 | }, | ||
166 | ast::UseTreeList(use_tree_list) => { | ||
167 | replace_node(replacement); | ||
168 | }, | ||
169 | ast::Use(use_item) => { | ||
170 | builder.replace_ast(use_item, ast::make::use_(replacement.left_or_else(|ut| ast::make::use_tree(path, Some(ut), None, false)))); | ||
171 | }, | ||
172 | _ => {}, | ||
173 | } | ||
174 | } | ||
175 | } | 166 | } |
176 | 167 | ||
177 | #[cfg(test)] | 168 | #[cfg(test)] |
@@ -260,7 +251,7 @@ fn qux(bar: Bar, baz: Baz) { | |||
260 | expand_glob_import, | 251 | expand_glob_import, |
261 | r" | 252 | r" |
262 | mod foo { | 253 | mod foo { |
263 | mod bar { | 254 | pub mod bar { |
264 | pub struct Bar; | 255 | pub struct Bar; |
265 | pub struct Baz; | 256 | pub struct Baz; |
266 | pub struct Qux; | 257 | pub struct Qux; |
@@ -268,7 +259,7 @@ mod foo { | |||
268 | pub fn f() {} | 259 | pub fn f() {} |
269 | } | 260 | } |
270 | 261 | ||
271 | mod baz { | 262 | pub mod baz { |
272 | pub fn g() {} | 263 | pub fn g() {} |
273 | } | 264 | } |
274 | } | 265 | } |
@@ -282,7 +273,7 @@ fn qux(bar: Bar, baz: Baz) { | |||
282 | ", | 273 | ", |
283 | r" | 274 | r" |
284 | mod foo { | 275 | mod foo { |
285 | mod bar { | 276 | pub mod bar { |
286 | pub struct Bar; | 277 | pub struct Bar; |
287 | pub struct Baz; | 278 | pub struct Baz; |
288 | pub struct Qux; | 279 | pub struct Qux; |
@@ -290,7 +281,7 @@ mod foo { | |||
290 | pub fn f() {} | 281 | pub fn f() {} |
291 | } | 282 | } |
292 | 283 | ||
293 | mod baz { | 284 | pub mod baz { |
294 | pub fn g() {} | 285 | pub fn g() {} |
295 | } | 286 | } |
296 | } | 287 | } |
@@ -302,7 +293,207 @@ fn qux(bar: Bar, baz: Baz) { | |||
302 | g(); | 293 | g(); |
303 | } | 294 | } |
304 | ", | 295 | ", |
305 | ) | 296 | ); |
297 | |||
298 | check_assist( | ||
299 | expand_glob_import, | ||
300 | r" | ||
301 | mod foo { | ||
302 | pub mod bar { | ||
303 | pub struct Bar; | ||
304 | pub struct Baz; | ||
305 | pub struct Qux; | ||
306 | |||
307 | pub fn f() {} | ||
308 | } | ||
309 | |||
310 | pub mod baz { | ||
311 | pub fn g() {} | ||
312 | } | ||
313 | } | ||
314 | |||
315 | use foo::{bar::{Bar, Baz, f}, baz::*<|>}; | ||
316 | |||
317 | fn qux(bar: Bar, baz: Baz) { | ||
318 | f(); | ||
319 | g(); | ||
320 | } | ||
321 | ", | ||
322 | r" | ||
323 | mod foo { | ||
324 | pub mod bar { | ||
325 | pub struct Bar; | ||
326 | pub struct Baz; | ||
327 | pub struct Qux; | ||
328 | |||
329 | pub fn f() {} | ||
330 | } | ||
331 | |||
332 | pub mod baz { | ||
333 | pub fn g() {} | ||
334 | } | ||
335 | } | ||
336 | |||
337 | use foo::{bar::{Bar, Baz, f}, baz::g}; | ||
338 | |||
339 | fn qux(bar: Bar, baz: Baz) { | ||
340 | f(); | ||
341 | g(); | ||
342 | } | ||
343 | ", | ||
344 | ); | ||
345 | |||
346 | check_assist( | ||
347 | expand_glob_import, | ||
348 | r" | ||
349 | mod foo { | ||
350 | pub mod bar { | ||
351 | pub struct Bar; | ||
352 | pub struct Baz; | ||
353 | pub struct Qux; | ||
354 | |||
355 | pub fn f() {} | ||
356 | } | ||
357 | |||
358 | pub mod baz { | ||
359 | pub fn g() {} | ||
360 | |||
361 | pub mod qux { | ||
362 | pub fn h() {} | ||
363 | pub fn m() {} | ||
364 | |||
365 | pub mod q { | ||
366 | pub fn j() {} | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | |||
372 | use foo::{ | ||
373 | bar::{*, f}, | ||
374 | baz::{g, qux::*<|>} | ||
375 | }; | ||
376 | |||
377 | fn qux(bar: Bar, baz: Baz) { | ||
378 | f(); | ||
379 | g(); | ||
380 | h(); | ||
381 | q::j(); | ||
382 | } | ||
383 | ", | ||
384 | r" | ||
385 | mod foo { | ||
386 | pub mod bar { | ||
387 | pub struct Bar; | ||
388 | pub struct Baz; | ||
389 | pub struct Qux; | ||
390 | |||
391 | pub fn f() {} | ||
392 | } | ||
393 | |||
394 | pub mod baz { | ||
395 | pub fn g() {} | ||
396 | |||
397 | pub mod qux { | ||
398 | pub fn h() {} | ||
399 | pub fn m() {} | ||
400 | |||
401 | pub mod q { | ||
402 | pub fn j() {} | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
408 | use foo::{ | ||
409 | bar::{*, f}, | ||
410 | baz::{g, qux::{q, h}} | ||
411 | }; | ||
412 | |||
413 | fn qux(bar: Bar, baz: Baz) { | ||
414 | f(); | ||
415 | g(); | ||
416 | h(); | ||
417 | q::j(); | ||
418 | } | ||
419 | ", | ||
420 | ); | ||
421 | |||
422 | check_assist( | ||
423 | expand_glob_import, | ||
424 | r" | ||
425 | mod foo { | ||
426 | pub mod bar { | ||
427 | pub struct Bar; | ||
428 | pub struct Baz; | ||
429 | pub struct Qux; | ||
430 | |||
431 | pub fn f() {} | ||
432 | } | ||
433 | |||
434 | pub mod baz { | ||
435 | pub fn g() {} | ||
436 | |||
437 | pub mod qux { | ||
438 | pub fn h() {} | ||
439 | pub fn m() {} | ||
440 | |||
441 | pub mod q { | ||
442 | pub fn j() {} | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | use foo::{ | ||
449 | bar::{*, f}, | ||
450 | baz::{g, qux::{h, q::*<|>}} | ||
451 | }; | ||
452 | |||
453 | fn qux(bar: Bar, baz: Baz) { | ||
454 | f(); | ||
455 | g(); | ||
456 | h(); | ||
457 | j(); | ||
458 | } | ||
459 | ", | ||
460 | r" | ||
461 | mod foo { | ||
462 | pub mod bar { | ||
463 | pub struct Bar; | ||
464 | pub struct Baz; | ||
465 | pub struct Qux; | ||
466 | |||
467 | pub fn f() {} | ||
468 | } | ||
469 | |||
470 | pub mod baz { | ||
471 | pub fn g() {} | ||
472 | |||
473 | pub mod qux { | ||
474 | pub fn h() {} | ||
475 | pub fn m() {} | ||
476 | |||
477 | pub mod q { | ||
478 | pub fn j() {} | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | use foo::{ | ||
485 | bar::{*, f}, | ||
486 | baz::{g, qux::{h, q::j}} | ||
487 | }; | ||
488 | |||
489 | fn qux(bar: Bar, baz: Baz) { | ||
490 | f(); | ||
491 | g(); | ||
492 | h(); | ||
493 | j(); | ||
494 | } | ||
495 | ", | ||
496 | ); | ||
306 | } | 497 | } |
307 | 498 | ||
308 | #[test] | 499 | #[test] |