diff options
Diffstat (limited to 'crates/ide_assists/src/handlers/expand_glob_import.rs')
-rw-r--r-- | crates/ide_assists/src/handlers/expand_glob_import.rs | 907 |
1 files changed, 907 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs new file mode 100644 index 000000000..5fe617ba4 --- /dev/null +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -0,0 +1,907 @@ | |||
1 | use either::Either; | ||
2 | use hir::{AssocItem, MacroDef, Module, ModuleDef, Name, PathResolution, ScopeDef}; | ||
3 | use ide_db::{ | ||
4 | defs::{Definition, NameRefClass}, | ||
5 | search::SearchScope, | ||
6 | }; | ||
7 | use syntax::{ | ||
8 | algo::SyntaxRewriter, | ||
9 | ast::{self, make}, | ||
10 | AstNode, Direction, SyntaxNode, SyntaxToken, T, | ||
11 | }; | ||
12 | |||
13 | use crate::{ | ||
14 | assist_context::{AssistContext, Assists}, | ||
15 | AssistId, AssistKind, | ||
16 | }; | ||
17 | |||
18 | // Assist: expand_glob_import | ||
19 | // | ||
20 | // Expands glob imports. | ||
21 | // | ||
22 | // ``` | ||
23 | // mod foo { | ||
24 | // pub struct Bar; | ||
25 | // pub struct Baz; | ||
26 | // } | ||
27 | // | ||
28 | // use foo::*$0; | ||
29 | // | ||
30 | // fn qux(bar: Bar, baz: Baz) {} | ||
31 | // ``` | ||
32 | // -> | ||
33 | // ``` | ||
34 | // mod foo { | ||
35 | // pub struct Bar; | ||
36 | // pub struct Baz; | ||
37 | // } | ||
38 | // | ||
39 | // use foo::{Baz, Bar}; | ||
40 | // | ||
41 | // fn qux(bar: Bar, baz: Baz) {} | ||
42 | // ``` | ||
43 | pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
44 | let star = ctx.find_token_syntax_at_offset(T![*])?; | ||
45 | let (parent, mod_path) = find_parent_and_path(&star)?; | ||
46 | let target_module = match ctx.sema.resolve_path(&mod_path)? { | ||
47 | PathResolution::Def(ModuleDef::Module(it)) => it, | ||
48 | _ => return None, | ||
49 | }; | ||
50 | |||
51 | let current_scope = ctx.sema.scope(&star.parent()); | ||
52 | let current_module = current_scope.module()?; | ||
53 | |||
54 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; | ||
55 | let imported_defs = find_imported_defs(ctx, star)?; | ||
56 | let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); | ||
57 | |||
58 | let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); | ||
59 | acc.add( | ||
60 | AssistId("expand_glob_import", AssistKind::RefactorRewrite), | ||
61 | "Expand glob import", | ||
62 | target.text_range(), | ||
63 | |builder| { | ||
64 | let mut rewriter = SyntaxRewriter::default(); | ||
65 | replace_ast(&mut rewriter, parent, mod_path, names_to_import); | ||
66 | builder.rewrite(rewriter); | ||
67 | }, | ||
68 | ) | ||
69 | } | ||
70 | |||
71 | fn find_parent_and_path( | ||
72 | star: &SyntaxToken, | ||
73 | ) -> Option<(Either<ast::UseTree, ast::UseTreeList>, ast::Path)> { | ||
74 | return star.ancestors().find_map(|n| { | ||
75 | find_use_tree_list(n.clone()) | ||
76 | .and_then(|(u, p)| Some((Either::Right(u), p))) | ||
77 | .or_else(|| find_use_tree(n).and_then(|(u, p)| Some((Either::Left(u), p)))) | ||
78 | }); | ||
79 | |||
80 | fn find_use_tree_list(n: SyntaxNode) -> Option<(ast::UseTreeList, ast::Path)> { | ||
81 | let use_tree_list = ast::UseTreeList::cast(n)?; | ||
82 | let path = use_tree_list.parent_use_tree().path()?; | ||
83 | Some((use_tree_list, path)) | ||
84 | } | ||
85 | |||
86 | fn find_use_tree(n: SyntaxNode) -> Option<(ast::UseTree, ast::Path)> { | ||
87 | let use_tree = ast::UseTree::cast(n)?; | ||
88 | let path = use_tree.path()?; | ||
89 | Some((use_tree, path)) | ||
90 | } | ||
91 | } | ||
92 | |||
93 | #[derive(Debug, PartialEq, Clone)] | ||
94 | enum Def { | ||
95 | ModuleDef(ModuleDef), | ||
96 | MacroDef(MacroDef), | ||
97 | } | ||
98 | |||
99 | impl Def { | ||
100 | fn is_referenced_in(&self, ctx: &AssistContext) -> bool { | ||
101 | let def = match self { | ||
102 | Def::ModuleDef(def) => Definition::ModuleDef(*def), | ||
103 | Def::MacroDef(def) => Definition::Macro(*def), | ||
104 | }; | ||
105 | |||
106 | let search_scope = SearchScope::single_file(ctx.frange.file_id); | ||
107 | def.usages(&ctx.sema).in_scope(search_scope).at_least_one() | ||
108 | } | ||
109 | } | ||
110 | |||
111 | #[derive(Debug, Clone)] | ||
112 | struct Ref { | ||
113 | // could be alias | ||
114 | visible_name: Name, | ||
115 | def: Def, | ||
116 | } | ||
117 | |||
118 | impl Ref { | ||
119 | fn from_scope_def(name: Name, scope_def: ScopeDef) -> Option<Self> { | ||
120 | match scope_def { | ||
121 | ScopeDef::ModuleDef(def) => Some(Ref { visible_name: name, def: Def::ModuleDef(def) }), | ||
122 | ScopeDef::MacroDef(def) => Some(Ref { visible_name: name, def: Def::MacroDef(def) }), | ||
123 | _ => None, | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #[derive(Debug, Clone)] | ||
129 | struct Refs(Vec<Ref>); | ||
130 | |||
131 | impl Refs { | ||
132 | fn used_refs(&self, ctx: &AssistContext) -> Refs { | ||
133 | Refs( | ||
134 | self.0 | ||
135 | .clone() | ||
136 | .into_iter() | ||
137 | .filter(|r| { | ||
138 | if let Def::ModuleDef(ModuleDef::Trait(tr)) = r.def { | ||
139 | if tr | ||
140 | .items(ctx.db()) | ||
141 | .into_iter() | ||
142 | .find(|ai| { | ||
143 | if let AssocItem::Function(f) = *ai { | ||
144 | Def::ModuleDef(ModuleDef::Function(f)).is_referenced_in(ctx) | ||
145 | } else { | ||
146 | false | ||
147 | } | ||
148 | }) | ||
149 | .is_some() | ||
150 | { | ||
151 | return true; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | r.def.is_referenced_in(ctx) | ||
156 | }) | ||
157 | .collect(), | ||
158 | ) | ||
159 | } | ||
160 | |||
161 | fn filter_out_by_defs(&self, defs: Vec<Def>) -> Refs { | ||
162 | Refs(self.0.clone().into_iter().filter(|r| !defs.contains(&r.def)).collect()) | ||
163 | } | ||
164 | } | ||
165 | |||
166 | fn find_refs_in_mod( | ||
167 | ctx: &AssistContext, | ||
168 | module: Module, | ||
169 | visible_from: Option<Module>, | ||
170 | ) -> Option<Refs> { | ||
171 | if let Some(from) = visible_from { | ||
172 | if !is_mod_visible_from(ctx, module, from) { | ||
173 | return None; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | let module_scope = module.scope(ctx.db(), visible_from); | ||
178 | let refs = module_scope.into_iter().filter_map(|(n, d)| Ref::from_scope_def(n, d)).collect(); | ||
179 | Some(Refs(refs)) | ||
180 | } | ||
181 | |||
182 | fn is_mod_visible_from(ctx: &AssistContext, module: Module, from: Module) -> bool { | ||
183 | match module.parent(ctx.db()) { | ||
184 | Some(parent) => { | ||
185 | parent.visibility_of(ctx.db(), &ModuleDef::Module(module)).map_or(true, |vis| { | ||
186 | vis.is_visible_from(ctx.db(), from.into()) && is_mod_visible_from(ctx, parent, from) | ||
187 | }) | ||
188 | } | ||
189 | None => true, | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // looks for name refs in parent use block's siblings | ||
194 | // | ||
195 | // mod bar { | ||
196 | // mod qux { | ||
197 | // struct Qux; | ||
198 | // } | ||
199 | // | ||
200 | // pub use qux::Qux; | ||
201 | // } | ||
202 | // | ||
203 | // ↓ --------------- | ||
204 | // use foo::*$0; | ||
205 | // use baz::Baz; | ||
206 | // ↑ --------------- | ||
207 | fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>> { | ||
208 | let parent_use_item_syntax = | ||
209 | star.ancestors().find_map(|n| if ast::Use::can_cast(n.kind()) { Some(n) } else { None })?; | ||
210 | |||
211 | Some( | ||
212 | [Direction::Prev, Direction::Next] | ||
213 | .iter() | ||
214 | .map(|dir| { | ||
215 | parent_use_item_syntax | ||
216 | .siblings(dir.to_owned()) | ||
217 | .filter(|n| ast::Use::can_cast(n.kind())) | ||
218 | }) | ||
219 | .flatten() | ||
220 | .filter_map(|n| Some(n.descendants().filter_map(ast::NameRef::cast))) | ||
221 | .flatten() | ||
222 | .filter_map(|r| match NameRefClass::classify(&ctx.sema, &r)? { | ||
223 | NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)), | ||
224 | NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)), | ||
225 | _ => None, | ||
226 | }) | ||
227 | .collect(), | ||
228 | ) | ||
229 | } | ||
230 | |||
231 | fn find_names_to_import( | ||
232 | ctx: &AssistContext, | ||
233 | refs_in_target: Refs, | ||
234 | imported_defs: Vec<Def>, | ||
235 | ) -> Vec<Name> { | ||
236 | let used_refs = refs_in_target.used_refs(ctx).filter_out_by_defs(imported_defs); | ||
237 | used_refs.0.iter().map(|r| r.visible_name.clone()).collect() | ||
238 | } | ||
239 | |||
240 | fn replace_ast( | ||
241 | rewriter: &mut SyntaxRewriter, | ||
242 | parent: Either<ast::UseTree, ast::UseTreeList>, | ||
243 | path: ast::Path, | ||
244 | names_to_import: Vec<Name>, | ||
245 | ) { | ||
246 | let existing_use_trees = match parent.clone() { | ||
247 | Either::Left(_) => vec![], | ||
248 | Either::Right(u) => u | ||
249 | .use_trees() | ||
250 | .filter(|n| | ||
251 | // filter out star | ||
252 | n.star_token().is_none()) | ||
253 | .collect(), | ||
254 | }; | ||
255 | |||
256 | let new_use_trees: Vec<ast::UseTree> = names_to_import | ||
257 | .iter() | ||
258 | .map(|n| { | ||
259 | let path = make::path_unqualified(make::path_segment(make::name_ref(&n.to_string()))); | ||
260 | make::use_tree(path, None, None, false) | ||
261 | }) | ||
262 | .collect(); | ||
263 | |||
264 | let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat(); | ||
265 | |||
266 | match use_trees.as_slice() { | ||
267 | [name] => { | ||
268 | if let Some(end_path) = name.path() { | ||
269 | rewriter.replace_ast( | ||
270 | &parent.left_or_else(|tl| tl.parent_use_tree()), | ||
271 | &make::use_tree(make::path_concat(path, end_path), None, None, false), | ||
272 | ); | ||
273 | } | ||
274 | } | ||
275 | names => match &parent { | ||
276 | Either::Left(parent) => rewriter.replace_ast( | ||
277 | parent, | ||
278 | &make::use_tree(path, Some(make::use_tree_list(names.to_owned())), None, false), | ||
279 | ), | ||
280 | Either::Right(parent) => { | ||
281 | rewriter.replace_ast(parent, &make::use_tree_list(names.to_owned())) | ||
282 | } | ||
283 | }, | ||
284 | }; | ||
285 | } | ||
286 | |||
287 | #[cfg(test)] | ||
288 | mod tests { | ||
289 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
290 | |||
291 | use super::*; | ||
292 | |||
293 | #[test] | ||
294 | fn expanding_glob_import() { | ||
295 | check_assist( | ||
296 | expand_glob_import, | ||
297 | r" | ||
298 | mod foo { | ||
299 | pub struct Bar; | ||
300 | pub struct Baz; | ||
301 | pub struct Qux; | ||
302 | |||
303 | pub fn f() {} | ||
304 | } | ||
305 | |||
306 | use foo::*$0; | ||
307 | |||
308 | fn qux(bar: Bar, baz: Baz) { | ||
309 | f(); | ||
310 | } | ||
311 | ", | ||
312 | r" | ||
313 | mod foo { | ||
314 | pub struct Bar; | ||
315 | pub struct Baz; | ||
316 | pub struct Qux; | ||
317 | |||
318 | pub fn f() {} | ||
319 | } | ||
320 | |||
321 | use foo::{Baz, Bar, f}; | ||
322 | |||
323 | fn qux(bar: Bar, baz: Baz) { | ||
324 | f(); | ||
325 | } | ||
326 | ", | ||
327 | ) | ||
328 | } | ||
329 | |||
330 | #[test] | ||
331 | fn expanding_glob_import_with_existing_explicit_names() { | ||
332 | check_assist( | ||
333 | expand_glob_import, | ||
334 | r" | ||
335 | mod foo { | ||
336 | pub struct Bar; | ||
337 | pub struct Baz; | ||
338 | pub struct Qux; | ||
339 | |||
340 | pub fn f() {} | ||
341 | } | ||
342 | |||
343 | use foo::{*$0, f}; | ||
344 | |||
345 | fn qux(bar: Bar, baz: Baz) { | ||
346 | f(); | ||
347 | } | ||
348 | ", | ||
349 | r" | ||
350 | mod foo { | ||
351 | pub struct Bar; | ||
352 | pub struct Baz; | ||
353 | pub struct Qux; | ||
354 | |||
355 | pub fn f() {} | ||
356 | } | ||
357 | |||
358 | use foo::{f, Baz, Bar}; | ||
359 | |||
360 | fn qux(bar: Bar, baz: Baz) { | ||
361 | f(); | ||
362 | } | ||
363 | ", | ||
364 | ) | ||
365 | } | ||
366 | |||
367 | #[test] | ||
368 | fn expanding_glob_import_with_existing_uses_in_same_module() { | ||
369 | check_assist( | ||
370 | expand_glob_import, | ||
371 | r" | ||
372 | mod foo { | ||
373 | pub struct Bar; | ||
374 | pub struct Baz; | ||
375 | pub struct Qux; | ||
376 | |||
377 | pub fn f() {} | ||
378 | } | ||
379 | |||
380 | use foo::Bar; | ||
381 | use foo::{*$0, f}; | ||
382 | |||
383 | fn qux(bar: Bar, baz: Baz) { | ||
384 | f(); | ||
385 | } | ||
386 | ", | ||
387 | r" | ||
388 | mod foo { | ||
389 | pub struct Bar; | ||
390 | pub struct Baz; | ||
391 | pub struct Qux; | ||
392 | |||
393 | pub fn f() {} | ||
394 | } | ||
395 | |||
396 | use foo::Bar; | ||
397 | use foo::{f, Baz}; | ||
398 | |||
399 | fn qux(bar: Bar, baz: Baz) { | ||
400 | f(); | ||
401 | } | ||
402 | ", | ||
403 | ) | ||
404 | } | ||
405 | |||
406 | #[test] | ||
407 | fn expanding_nested_glob_import() { | ||
408 | check_assist( | ||
409 | expand_glob_import, | ||
410 | r" | ||
411 | mod foo { | ||
412 | pub mod bar { | ||
413 | pub struct Bar; | ||
414 | pub struct Baz; | ||
415 | pub struct Qux; | ||
416 | |||
417 | pub fn f() {} | ||
418 | } | ||
419 | |||
420 | pub mod baz { | ||
421 | pub fn g() {} | ||
422 | } | ||
423 | } | ||
424 | |||
425 | use foo::{bar::{*$0, f}, baz::*}; | ||
426 | |||
427 | fn qux(bar: Bar, baz: Baz) { | ||
428 | f(); | ||
429 | g(); | ||
430 | } | ||
431 | ", | ||
432 | r" | ||
433 | mod foo { | ||
434 | pub mod bar { | ||
435 | pub struct Bar; | ||
436 | pub struct Baz; | ||
437 | pub struct Qux; | ||
438 | |||
439 | pub fn f() {} | ||
440 | } | ||
441 | |||
442 | pub mod baz { | ||
443 | pub fn g() {} | ||
444 | } | ||
445 | } | ||
446 | |||
447 | use foo::{bar::{f, Baz, Bar}, baz::*}; | ||
448 | |||
449 | fn qux(bar: Bar, baz: Baz) { | ||
450 | f(); | ||
451 | g(); | ||
452 | } | ||
453 | ", | ||
454 | ); | ||
455 | |||
456 | check_assist( | ||
457 | expand_glob_import, | ||
458 | r" | ||
459 | mod foo { | ||
460 | pub mod bar { | ||
461 | pub struct Bar; | ||
462 | pub struct Baz; | ||
463 | pub struct Qux; | ||
464 | |||
465 | pub fn f() {} | ||
466 | } | ||
467 | |||
468 | pub mod baz { | ||
469 | pub fn g() {} | ||
470 | } | ||
471 | } | ||
472 | |||
473 | use foo::{bar::{Bar, Baz, f}, baz::*$0}; | ||
474 | |||
475 | fn qux(bar: Bar, baz: Baz) { | ||
476 | f(); | ||
477 | g(); | ||
478 | } | ||
479 | ", | ||
480 | r" | ||
481 | mod foo { | ||
482 | pub mod bar { | ||
483 | pub struct Bar; | ||
484 | pub struct Baz; | ||
485 | pub struct Qux; | ||
486 | |||
487 | pub fn f() {} | ||
488 | } | ||
489 | |||
490 | pub mod baz { | ||
491 | pub fn g() {} | ||
492 | } | ||
493 | } | ||
494 | |||
495 | use foo::{bar::{Bar, Baz, f}, baz::g}; | ||
496 | |||
497 | fn qux(bar: Bar, baz: Baz) { | ||
498 | f(); | ||
499 | g(); | ||
500 | } | ||
501 | ", | ||
502 | ); | ||
503 | |||
504 | check_assist( | ||
505 | expand_glob_import, | ||
506 | r" | ||
507 | mod foo { | ||
508 | pub mod bar { | ||
509 | pub struct Bar; | ||
510 | pub struct Baz; | ||
511 | pub struct Qux; | ||
512 | |||
513 | pub fn f() {} | ||
514 | } | ||
515 | |||
516 | pub mod baz { | ||
517 | pub fn g() {} | ||
518 | |||
519 | pub mod qux { | ||
520 | pub fn h() {} | ||
521 | pub fn m() {} | ||
522 | |||
523 | pub mod q { | ||
524 | pub fn j() {} | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | use foo::{ | ||
531 | bar::{*, f}, | ||
532 | baz::{g, qux::*$0} | ||
533 | }; | ||
534 | |||
535 | fn qux(bar: Bar, baz: Baz) { | ||
536 | f(); | ||
537 | g(); | ||
538 | h(); | ||
539 | q::j(); | ||
540 | } | ||
541 | ", | ||
542 | r" | ||
543 | mod foo { | ||
544 | pub mod bar { | ||
545 | pub struct Bar; | ||
546 | pub struct Baz; | ||
547 | pub struct Qux; | ||
548 | |||
549 | pub fn f() {} | ||
550 | } | ||
551 | |||
552 | pub mod baz { | ||
553 | pub fn g() {} | ||
554 | |||
555 | pub mod qux { | ||
556 | pub fn h() {} | ||
557 | pub fn m() {} | ||
558 | |||
559 | pub mod q { | ||
560 | pub fn j() {} | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | use foo::{ | ||
567 | bar::{*, f}, | ||
568 | baz::{g, qux::{q, h}} | ||
569 | }; | ||
570 | |||
571 | fn qux(bar: Bar, baz: Baz) { | ||
572 | f(); | ||
573 | g(); | ||
574 | h(); | ||
575 | q::j(); | ||
576 | } | ||
577 | ", | ||
578 | ); | ||
579 | |||
580 | check_assist( | ||
581 | expand_glob_import, | ||
582 | r" | ||
583 | mod foo { | ||
584 | pub mod bar { | ||
585 | pub struct Bar; | ||
586 | pub struct Baz; | ||
587 | pub struct Qux; | ||
588 | |||
589 | pub fn f() {} | ||
590 | } | ||
591 | |||
592 | pub mod baz { | ||
593 | pub fn g() {} | ||
594 | |||
595 | pub mod qux { | ||
596 | pub fn h() {} | ||
597 | pub fn m() {} | ||
598 | |||
599 | pub mod q { | ||
600 | pub fn j() {} | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | use foo::{ | ||
607 | bar::{*, f}, | ||
608 | baz::{g, qux::{h, q::*$0}} | ||
609 | }; | ||
610 | |||
611 | fn qux(bar: Bar, baz: Baz) { | ||
612 | f(); | ||
613 | g(); | ||
614 | h(); | ||
615 | j(); | ||
616 | } | ||
617 | ", | ||
618 | r" | ||
619 | mod foo { | ||
620 | pub mod bar { | ||
621 | pub struct Bar; | ||
622 | pub struct Baz; | ||
623 | pub struct Qux; | ||
624 | |||
625 | pub fn f() {} | ||
626 | } | ||
627 | |||
628 | pub mod baz { | ||
629 | pub fn g() {} | ||
630 | |||
631 | pub mod qux { | ||
632 | pub fn h() {} | ||
633 | pub fn m() {} | ||
634 | |||
635 | pub mod q { | ||
636 | pub fn j() {} | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | use foo::{ | ||
643 | bar::{*, f}, | ||
644 | baz::{g, qux::{h, q::j}} | ||
645 | }; | ||
646 | |||
647 | fn qux(bar: Bar, baz: Baz) { | ||
648 | f(); | ||
649 | g(); | ||
650 | h(); | ||
651 | j(); | ||
652 | } | ||
653 | ", | ||
654 | ); | ||
655 | |||
656 | check_assist( | ||
657 | expand_glob_import, | ||
658 | r" | ||
659 | mod foo { | ||
660 | pub mod bar { | ||
661 | pub struct Bar; | ||
662 | pub struct Baz; | ||
663 | pub struct Qux; | ||
664 | |||
665 | pub fn f() {} | ||
666 | } | ||
667 | |||
668 | pub mod baz { | ||
669 | pub fn g() {} | ||
670 | |||
671 | pub mod qux { | ||
672 | pub fn h() {} | ||
673 | pub fn m() {} | ||
674 | |||
675 | pub mod q { | ||
676 | pub fn j() {} | ||
677 | } | ||
678 | } | ||
679 | } | ||
680 | } | ||
681 | |||
682 | use foo::{ | ||
683 | bar::{*, f}, | ||
684 | baz::{g, qux::{q::j, *$0}} | ||
685 | }; | ||
686 | |||
687 | fn qux(bar: Bar, baz: Baz) { | ||
688 | f(); | ||
689 | g(); | ||
690 | h(); | ||
691 | j(); | ||
692 | } | ||
693 | ", | ||
694 | r" | ||
695 | mod foo { | ||
696 | pub mod bar { | ||
697 | pub struct Bar; | ||
698 | pub struct Baz; | ||
699 | pub struct Qux; | ||
700 | |||
701 | pub fn f() {} | ||
702 | } | ||
703 | |||
704 | pub mod baz { | ||
705 | pub fn g() {} | ||
706 | |||
707 | pub mod qux { | ||
708 | pub fn h() {} | ||
709 | pub fn m() {} | ||
710 | |||
711 | pub mod q { | ||
712 | pub fn j() {} | ||
713 | } | ||
714 | } | ||
715 | } | ||
716 | } | ||
717 | |||
718 | use foo::{ | ||
719 | bar::{*, f}, | ||
720 | baz::{g, qux::{q::j, h}} | ||
721 | }; | ||
722 | |||
723 | fn qux(bar: Bar, baz: Baz) { | ||
724 | f(); | ||
725 | g(); | ||
726 | h(); | ||
727 | j(); | ||
728 | } | ||
729 | ", | ||
730 | ); | ||
731 | } | ||
732 | |||
733 | #[test] | ||
734 | fn expanding_glob_import_with_macro_defs() { | ||
735 | // FIXME: this is currently fails because `Definition::find_usages` ignores macros | ||
736 | // https://github.com/rust-analyzer/rust-analyzer/issues/3484 | ||
737 | // | ||
738 | // check_assist( | ||
739 | // expand_glob_import, | ||
740 | // r" | ||
741 | // //- /lib.rs crate:foo | ||
742 | // #[macro_export] | ||
743 | // macro_rules! bar { | ||
744 | // () => () | ||
745 | // } | ||
746 | |||
747 | // pub fn baz() {} | ||
748 | |||
749 | // //- /main.rs crate:main deps:foo | ||
750 | // use foo::*$0; | ||
751 | |||
752 | // fn main() { | ||
753 | // bar!(); | ||
754 | // baz(); | ||
755 | // } | ||
756 | // ", | ||
757 | // r" | ||
758 | // use foo::{bar, baz}; | ||
759 | |||
760 | // fn main() { | ||
761 | // bar!(); | ||
762 | // baz(); | ||
763 | // } | ||
764 | // ", | ||
765 | // ) | ||
766 | } | ||
767 | |||
768 | #[test] | ||
769 | fn expanding_glob_import_with_trait_method_uses() { | ||
770 | check_assist( | ||
771 | expand_glob_import, | ||
772 | r" | ||
773 | //- /lib.rs crate:foo | ||
774 | pub trait Tr { | ||
775 | fn method(&self) {} | ||
776 | } | ||
777 | impl Tr for () {} | ||
778 | |||
779 | //- /main.rs crate:main deps:foo | ||
780 | use foo::*$0; | ||
781 | |||
782 | fn main() { | ||
783 | ().method(); | ||
784 | } | ||
785 | ", | ||
786 | r" | ||
787 | use foo::Tr; | ||
788 | |||
789 | fn main() { | ||
790 | ().method(); | ||
791 | } | ||
792 | ", | ||
793 | ); | ||
794 | |||
795 | check_assist( | ||
796 | expand_glob_import, | ||
797 | r" | ||
798 | //- /lib.rs crate:foo | ||
799 | pub trait Tr { | ||
800 | fn method(&self) {} | ||
801 | } | ||
802 | impl Tr for () {} | ||
803 | |||
804 | pub trait Tr2 { | ||
805 | fn method2(&self) {} | ||
806 | } | ||
807 | impl Tr2 for () {} | ||
808 | |||
809 | //- /main.rs crate:main deps:foo | ||
810 | use foo::*$0; | ||
811 | |||
812 | fn main() { | ||
813 | ().method(); | ||
814 | } | ||
815 | ", | ||
816 | r" | ||
817 | use foo::Tr; | ||
818 | |||
819 | fn main() { | ||
820 | ().method(); | ||
821 | } | ||
822 | ", | ||
823 | ); | ||
824 | } | ||
825 | |||
826 | #[test] | ||
827 | fn expanding_is_not_applicable_if_target_module_is_not_accessible_from_current_scope() { | ||
828 | check_assist_not_applicable( | ||
829 | expand_glob_import, | ||
830 | r" | ||
831 | mod foo { | ||
832 | mod bar { | ||
833 | pub struct Bar; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | use foo::bar::*$0; | ||
838 | |||
839 | fn baz(bar: Bar) {} | ||
840 | ", | ||
841 | ); | ||
842 | |||
843 | check_assist_not_applicable( | ||
844 | expand_glob_import, | ||
845 | r" | ||
846 | mod foo { | ||
847 | mod bar { | ||
848 | pub mod baz { | ||
849 | pub struct Baz; | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | use foo::bar::baz::*$0; | ||
855 | |||
856 | fn qux(baz: Baz) {} | ||
857 | ", | ||
858 | ); | ||
859 | } | ||
860 | |||
861 | #[test] | ||
862 | fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() { | ||
863 | check_assist_not_applicable( | ||
864 | expand_glob_import, | ||
865 | r" | ||
866 | mod foo { | ||
867 | pub struct Bar; | ||
868 | pub struct Baz; | ||
869 | pub struct Qux; | ||
870 | } | ||
871 | |||
872 | use foo::Bar$0; | ||
873 | |||
874 | fn qux(bar: Bar, baz: Baz) {} | ||
875 | ", | ||
876 | ) | ||
877 | } | ||
878 | |||
879 | #[test] | ||
880 | fn expanding_glob_import_single_nested_glob_only() { | ||
881 | check_assist( | ||
882 | expand_glob_import, | ||
883 | r" | ||
884 | mod foo { | ||
885 | pub struct Bar; | ||
886 | } | ||
887 | |||
888 | use foo::{*$0}; | ||
889 | |||
890 | struct Baz { | ||
891 | bar: Bar | ||
892 | } | ||
893 | ", | ||
894 | r" | ||
895 | mod foo { | ||
896 | pub struct Bar; | ||
897 | } | ||
898 | |||
899 | use foo::Bar; | ||
900 | |||
901 | struct Baz { | ||
902 | bar: Bar | ||
903 | } | ||
904 | ", | ||
905 | ); | ||
906 | } | ||
907 | } | ||