1use either::Either;
2use hir::{AssocItem, Enum, HasVisibility, Module, ModuleDef, Name, PathResolution, ScopeDef};
3use ide_db::{
4 defs::{Definition, NameRefClass},
5 search::SearchScope,
6 source_change::SourceChangeBuilder,
7};
8use stdx::never;
9use syntax::{
10 AstNode, Direction, SyntaxNode, SyntaxToken, T,
11 ast::{self, Use, UseTree, VisibilityKind},
12};
13
14use crate::{
15 AssistId,
16 assist_context::{AssistContext, Assists},
17};
18
19pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
45 let star = ctx.find_token_syntax_at_offset(T![*])?;
46 let use_tree = star.parent().and_then(ast::UseTree::cast)?;
47 let use_item = star.parent_ancestors().find_map(ast::Use::cast)?;
48 let (parent, mod_path) = find_parent_and_path(&star)?;
49 let target_module = match ctx.sema.resolve_path(&mod_path)? {
50 PathResolution::Def(ModuleDef::Module(it)) => Expandable::Module(it),
51 PathResolution::Def(ModuleDef::Adt(hir::Adt::Enum(e))) => Expandable::Enum(e),
52 _ => return None,
53 };
54
55 let current_scope = ctx.sema.scope(&star.parent()?)?;
56 let current_module = current_scope.module();
57
58 if !is_visible_from(ctx, &target_module, current_module) {
59 return None;
60 }
61
62 let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
63 acc.add(
64 AssistId::refactor_rewrite("expand_glob_import"),
65 "Expand glob import",
66 target.text_range(),
67 |builder| {
68 build_expanded_import(
69 ctx,
70 builder,
71 use_tree,
72 use_item,
73 target_module,
74 current_module,
75 false,
76 )
77 },
78 )
79}
80
81pub(crate) fn expand_glob_reexport(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
103 let star = ctx.find_token_syntax_at_offset(T![*])?;
104 let use_tree = star.parent().and_then(ast::UseTree::cast)?;
105 let use_item = star.parent_ancestors().find_map(ast::Use::cast)?;
106 let (parent, mod_path) = find_parent_and_path(&star)?;
107 let target_module = match ctx.sema.resolve_path(&mod_path)? {
108 PathResolution::Def(ModuleDef::Module(it)) => Expandable::Module(it),
109 PathResolution::Def(ModuleDef::Adt(hir::Adt::Enum(e))) => Expandable::Enum(e),
110 _ => return None,
111 };
112
113 let current_scope = ctx.sema.scope(&star.parent()?)?;
114 let current_module = current_scope.module();
115
116 if let VisibilityKind::PubSelf = get_export_visibility_kind(&use_item) {
117 return None;
118 }
119 if !is_visible_from(ctx, &target_module, current_module) {
120 return None;
121 }
122
123 let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone());
124 acc.add(
125 AssistId::refactor_rewrite("expand_glob_reexport"),
126 "Expand glob reexport",
127 target.text_range(),
128 |builder| {
129 build_expanded_import(
130 ctx,
131 builder,
132 use_tree,
133 use_item,
134 target_module,
135 current_module,
136 true,
137 )
138 },
139 )
140}
141
142fn build_expanded_import(
143 ctx: &AssistContext<'_, '_>,
144 builder: &mut SourceChangeBuilder,
145 use_tree: UseTree,
146 use_item: Use,
147 target_module: Expandable,
148 current_module: Module,
149 reexport_public_items: bool,
150) {
151 let editor = builder.make_editor(use_tree.syntax());
152 let make = editor.make();
153 let (must_be_pub, visible_from) = if !reexport_public_items {
154 (false, current_module)
155 } else {
156 match get_export_visibility_kind(&use_item) {
157 VisibilityKind::Pub => (true, current_module.krate(ctx.db()).root_module(ctx.db())),
158 VisibilityKind::PubCrate => {
159 (false, current_module.krate(ctx.db()).root_module(ctx.db()))
160 }
161 _ => (false, current_module),
162 }
163 };
164
165 let refs_in_target =
166 find_refs_in_mod(ctx, target_module, current_module, visible_from, must_be_pub);
167 let imported_defs = find_imported_defs(ctx, use_item);
168
169 let filtered_defs =
170 if reexport_public_items { refs_in_target } else { refs_in_target.used_refs(ctx) };
171
172 let names_to_import = find_names_to_import(filtered_defs, imported_defs);
173 let expanded = make.use_tree_list(names_to_import.iter().map(|n| {
174 let path = make.ident_path(
175 &n.display(ctx.db(), current_module.krate(ctx.db()).edition(ctx.db())).to_string(),
176 );
177 make.use_tree(path, None, None, false)
178 }));
179
180 match use_tree.star_token() {
181 Some(star) => {
182 let needs_braces = use_tree.path().is_some() && names_to_import.len() != 1;
183 if needs_braces {
184 editor.replace(star, expanded.syntax())
185 } else {
186 let without_braces = expanded
187 .syntax()
188 .children_with_tokens()
189 .filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
190 .collect();
191 editor.replace_with_many(star, without_braces)
192 }
193 }
194 None => never!(),
195 }
196 builder.add_file_edits(ctx.vfs_file_id(), editor);
197}
198
199fn get_export_visibility_kind(use_item: &Use) -> VisibilityKind {
200 use syntax::ast::HasVisibility as _;
201 match use_item.visibility() {
202 Some(vis) => match vis.kind() {
203 VisibilityKind::PubCrate => VisibilityKind::PubCrate,
204 VisibilityKind::Pub => VisibilityKind::Pub,
205 VisibilityKind::PubSelf => VisibilityKind::PubSelf,
206 VisibilityKind::In(_) => VisibilityKind::PubSelf,
208 VisibilityKind::PubSuper => VisibilityKind::PubSelf,
209 },
210 None => VisibilityKind::PubSelf,
211 }
212}
213
214enum Expandable {
215 Module(Module),
216 Enum(Enum),
217}
218
219fn find_parent_and_path(
220 star: &SyntaxToken,
221) -> Option<(Either<ast::UseTree, ast::UseTreeList>, ast::Path)> {
222 return star.parent_ancestors().find_map(|n| {
223 find_use_tree_list(n.clone())
224 .map(|(u, p)| (Either::Right(u), p))
225 .or_else(|| find_use_tree(n).map(|(u, p)| (Either::Left(u), p)))
226 });
227
228 fn find_use_tree_list(n: SyntaxNode) -> Option<(ast::UseTreeList, ast::Path)> {
229 let use_tree_list = ast::UseTreeList::cast(n)?;
230 let path = use_tree_list.parent_use_tree().path()?;
231 Some((use_tree_list, path))
232 }
233
234 fn find_use_tree(n: SyntaxNode) -> Option<(ast::UseTree, ast::Path)> {
235 let use_tree = ast::UseTree::cast(n)?;
236 let path = use_tree.path()?;
237 Some((use_tree, path))
238 }
239}
240
241fn def_is_referenced_in(def: Definition, ctx: &AssistContext<'_, '_>) -> bool {
242 let search_scope = SearchScope::single_file(ctx.file_id());
243 def.usages(&ctx.sema).in_scope(&search_scope).at_least_one()
244}
245
246#[derive(Debug, Clone)]
247struct Ref {
248 visible_name: Name,
250 def: Definition,
251 is_pub: bool,
252}
253
254impl Ref {
255 fn from_scope_def(
256 ctx: &AssistContext<'_, '_>,
257 name: Name,
258 scope_def: ScopeDef,
259 ) -> Option<Self> {
260 match scope_def {
261 ScopeDef::ModuleDef(def) => Some(Ref {
262 visible_name: name,
263 def: Definition::from(def),
264 is_pub: matches!(def.visibility(ctx.db()), hir::Visibility::Public),
265 }),
266 _ => None,
267 }
268 }
269}
270
271#[derive(Debug, Clone)]
272struct Refs(Vec<Ref>);
273
274impl Refs {
275 fn used_refs(&self, ctx: &AssistContext<'_, '_>) -> Refs {
276 Refs(
277 self.0
278 .clone()
279 .into_iter()
280 .filter(|r| {
281 if let Definition::Trait(tr) = r.def
282 && tr.items(ctx.db()).into_iter().any(|ai| {
283 if let AssocItem::Function(f) = ai {
284 def_is_referenced_in(Definition::Function(f), ctx)
285 } else {
286 false
287 }
288 })
289 {
290 return true;
291 }
292
293 def_is_referenced_in(r.def, ctx)
294 })
295 .collect(),
296 )
297 }
298
299 fn filter_out_by_defs(&self, defs: Vec<Definition>) -> Refs {
300 Refs(self.0.clone().into_iter().filter(|r| !defs.contains(&r.def)).collect())
301 }
302}
303
304fn find_refs_in_mod(
305 ctx: &AssistContext<'_, '_>,
306 expandable: Expandable,
307 current_module: Module,
308 visible_from: Module,
309 must_be_pub: bool,
310) -> Refs {
311 match expandable {
312 Expandable::Module(module) => {
313 let module_scope = module.scope(ctx.db(), Some(visible_from));
314 let refs = module_scope
315 .into_iter()
316 .filter_map(|(n, d)| Ref::from_scope_def(ctx, n, d))
317 .filter(|r| match r.def {
318 Definition::Module(it) => it != current_module,
319 _ => r.def.module(ctx.db()).map_or(false, |it| it != current_module),
320 })
321 .filter(|r| !must_be_pub || r.is_pub)
322 .collect();
323 Refs(refs)
324 }
325 Expandable::Enum(enm) => Refs(
326 enm.variants(ctx.db())
327 .into_iter()
328 .map(|v| Ref {
329 visible_name: v.name(ctx.db()),
330 def: Definition::EnumVariant(v),
331 is_pub: true,
332 })
333 .collect(),
334 ),
335 }
336}
337
338fn is_visible_from(ctx: &AssistContext<'_, '_>, expandable: &Expandable, from: Module) -> bool {
339 fn is_mod_visible_from(ctx: &AssistContext<'_, '_>, module: Module, from: Module) -> bool {
340 match module.parent(ctx.db()) {
341 Some(parent) => {
342 module.visibility(ctx.db()).is_visible_from(ctx.db(), from.into())
343 && is_mod_visible_from(ctx, parent, from)
344 }
345 None => true,
346 }
347 }
348
349 match expandable {
350 Expandable::Module(module) => match module.parent(ctx.db()) {
351 Some(parent) => {
352 module.visibility(ctx.db()).is_visible_from(ctx.db(), from.into())
353 && is_mod_visible_from(ctx, parent, from)
354 }
355 None => true,
356 },
357 Expandable::Enum(enm) => {
358 let module = enm.module(ctx.db());
359 enm.visibility(ctx.db()).is_visible_from(ctx.db(), from.into())
360 && is_mod_visible_from(ctx, module, from)
361 }
362 }
363}
364
365fn find_imported_defs(ctx: &AssistContext<'_, '_>, use_item: Use) -> Vec<Definition> {
380 [Direction::Prev, Direction::Next]
381 .into_iter()
382 .flat_map(|dir| {
383 use_item.syntax().siblings(dir.to_owned()).filter(|n| ast::Use::can_cast(n.kind()))
384 })
385 .flat_map(|n| n.descendants().filter_map(ast::NameRef::cast))
386 .filter_map(|r| match NameRefClass::classify(&ctx.sema, &r)? {
387 NameRefClass::Definition(
388 def @ (Definition::Macro(_)
389 | Definition::Module(_)
390 | Definition::Function(_)
391 | Definition::Adt(_)
392 | Definition::EnumVariant(_)
393 | Definition::Const(_)
394 | Definition::Static(_)
395 | Definition::Trait(_)
396 | Definition::TypeAlias(_)),
397 _,
398 ) => Some(def),
399 _ => None,
400 })
401 .collect()
402}
403
404fn find_names_to_import(refs_in_target: Refs, imported_defs: Vec<Definition>) -> Vec<Name> {
405 let final_refs = refs_in_target.filter_out_by_defs(imported_defs);
406 final_refs.0.iter().map(|r| r.visible_name.clone()).collect()
407}
408
409#[cfg(test)]
410mod tests {
411 use crate::tests::{check_assist, check_assist_not_applicable};
412
413 use super::*;
414
415 #[test]
416 fn expanding_glob_import() {
417 check_assist(
418 expand_glob_import,
419 r"
420mod foo {
421 pub struct Bar;
422 pub struct Baz;
423 pub struct Qux;
424
425 pub fn f() {}
426}
427
428use foo::*$0;
429
430fn qux(bar: Bar, baz: Baz) {
431 f();
432}
433",
434 r"
435mod foo {
436 pub struct Bar;
437 pub struct Baz;
438 pub struct Qux;
439
440 pub fn f() {}
441}
442
443use foo::{Bar, Baz, f};
444
445fn qux(bar: Bar, baz: Baz) {
446 f();
447}
448",
449 )
450 }
451
452 #[test]
453 fn expanding_glob_import_on_cycle_import() {
454 check_assist(
455 expand_glob_import,
456 r"
457mod foo {
458 pub use crate::*$0;
459 pub struct Foo;
460 pub fn bar() -> Bar { _ = Foo; Bar }
461}
462pub use foo::*;
463pub struct Bar;
464",
465 r"
466mod foo {
467 pub use crate::Bar;
468 pub struct Foo;
469 pub fn bar() -> Bar { _ = Foo; Bar }
470}
471pub use foo::*;
472pub struct Bar;
473",
474 )
475 }
476
477 #[test]
478 fn expanding_glob_import_unused() {
479 check_assist(
480 expand_glob_import,
481 r"
482mod foo {
483 pub struct Bar;
484 pub struct Baz;
485 pub struct Qux;
486
487 pub fn f() {}
488}
489
490use foo::*$0;
491
492fn qux() {}
493",
494 r"
495mod foo {
496 pub struct Bar;
497 pub struct Baz;
498 pub struct Qux;
499
500 pub fn f() {}
501}
502
503use foo::{};
504
505fn qux() {}
506",
507 )
508 }
509
510 #[test]
511 fn expanding_glob_import_with_existing_explicit_names() {
512 check_assist(
513 expand_glob_import,
514 r"
515mod foo {
516 pub struct Bar;
517 pub struct Baz;
518 pub struct Qux;
519
520 pub fn f() {}
521}
522
523use foo::{*$0, f};
524
525fn qux(bar: Bar, baz: Baz) {
526 f();
527}
528",
529 r"
530mod foo {
531 pub struct Bar;
532 pub struct Baz;
533 pub struct Qux;
534
535 pub fn f() {}
536}
537
538use foo::{Bar, Baz, f};
539
540fn qux(bar: Bar, baz: Baz) {
541 f();
542}
543",
544 )
545 }
546
547 #[test]
548 fn expanding_glob_import_with_existing_uses_in_same_module() {
549 check_assist(
550 expand_glob_import,
551 r"
552mod foo {
553 pub struct Bar;
554 pub struct Baz;
555 pub struct Qux;
556
557 pub fn f() {}
558}
559
560use foo::Bar;
561use foo::{*$0, f};
562
563fn qux(bar: Bar, baz: Baz) {
564 f();
565}
566",
567 r"
568mod foo {
569 pub struct Bar;
570 pub struct Baz;
571 pub struct Qux;
572
573 pub fn f() {}
574}
575
576use foo::Bar;
577use foo::{Baz, f};
578
579fn qux(bar: Bar, baz: Baz) {
580 f();
581}
582",
583 )
584 }
585
586 #[test]
587 fn expanding_nested_glob_import() {
588 check_assist(
589 expand_glob_import,
590 r"
591mod foo {
592 pub mod bar {
593 pub struct Bar;
594 pub struct Baz;
595 pub struct Qux;
596
597 pub fn f() {}
598 }
599
600 pub mod baz {
601 pub fn g() {}
602 }
603}
604
605use foo::{bar::{*$0, f}, baz::*};
606
607fn qux(bar: Bar, baz: Baz) {
608 f();
609 g();
610}
611",
612 r"
613mod foo {
614 pub mod bar {
615 pub struct Bar;
616 pub struct Baz;
617 pub struct Qux;
618
619 pub fn f() {}
620 }
621
622 pub mod baz {
623 pub fn g() {}
624 }
625}
626
627use foo::{bar::{Bar, Baz, f}, baz::*};
628
629fn qux(bar: Bar, baz: Baz) {
630 f();
631 g();
632}
633",
634 );
635
636 check_assist(
637 expand_glob_import,
638 r"
639mod foo {
640 pub mod bar {
641 pub struct Bar;
642 pub struct Baz;
643 pub struct Qux;
644
645 pub fn f() {}
646 }
647
648 pub mod baz {
649 pub fn g() {}
650 }
651}
652
653use foo::{bar::{Bar, Baz, f}, baz::*$0};
654
655fn qux(bar: Bar, baz: Baz) {
656 f();
657 g();
658}
659",
660 r"
661mod foo {
662 pub mod bar {
663 pub struct Bar;
664 pub struct Baz;
665 pub struct Qux;
666
667 pub fn f() {}
668 }
669
670 pub mod baz {
671 pub fn g() {}
672 }
673}
674
675use foo::{bar::{Bar, Baz, f}, baz::g};
676
677fn qux(bar: Bar, baz: Baz) {
678 f();
679 g();
680}
681",
682 );
683
684 check_assist(
685 expand_glob_import,
686 r"
687mod foo {
688 pub mod bar {
689 pub struct Bar;
690 pub struct Baz;
691 pub struct Qux;
692
693 pub fn f() {}
694 }
695
696 pub mod baz {
697 pub fn g() {}
698
699 pub mod qux {
700 pub fn h() {}
701 pub fn m() {}
702
703 pub mod q {
704 pub fn j() {}
705 }
706 }
707 }
708}
709
710use foo::{
711 bar::{*, f},
712 baz::{g, qux::*$0}
713};
714
715fn qux(bar: Bar, baz: Baz) {
716 f();
717 g();
718 h();
719 q::j();
720}
721",
722 r"
723mod foo {
724 pub mod bar {
725 pub struct Bar;
726 pub struct Baz;
727 pub struct Qux;
728
729 pub fn f() {}
730 }
731
732 pub mod baz {
733 pub fn g() {}
734
735 pub mod qux {
736 pub fn h() {}
737 pub fn m() {}
738
739 pub mod q {
740 pub fn j() {}
741 }
742 }
743 }
744}
745
746use foo::{
747 bar::{*, f},
748 baz::{g, qux::{h, q}}
749};
750
751fn qux(bar: Bar, baz: Baz) {
752 f();
753 g();
754 h();
755 q::j();
756}
757",
758 );
759
760 check_assist(
761 expand_glob_import,
762 r"
763mod foo {
764 pub mod bar {
765 pub struct Bar;
766 pub struct Baz;
767 pub struct Qux;
768
769 pub fn f() {}
770 }
771
772 pub mod baz {
773 pub fn g() {}
774
775 pub mod qux {
776 pub fn h() {}
777 pub fn m() {}
778
779 pub mod q {
780 pub fn j() {}
781 }
782 }
783 }
784}
785
786use foo::{
787 bar::{*, f},
788 baz::{g, qux::{h, q::*$0}}
789};
790
791fn qux(bar: Bar, baz: Baz) {
792 f();
793 g();
794 h();
795 j();
796}
797",
798 r"
799mod foo {
800 pub mod bar {
801 pub struct Bar;
802 pub struct Baz;
803 pub struct Qux;
804
805 pub fn f() {}
806 }
807
808 pub mod baz {
809 pub fn g() {}
810
811 pub mod qux {
812 pub fn h() {}
813 pub fn m() {}
814
815 pub mod q {
816 pub fn j() {}
817 }
818 }
819 }
820}
821
822use foo::{
823 bar::{*, f},
824 baz::{g, qux::{h, q::j}}
825};
826
827fn qux(bar: Bar, baz: Baz) {
828 f();
829 g();
830 h();
831 j();
832}
833",
834 );
835
836 check_assist(
837 expand_glob_import,
838 r"
839mod foo {
840 pub mod bar {
841 pub struct Bar;
842 pub struct Baz;
843 pub struct Qux;
844
845 pub fn f() {}
846 }
847
848 pub mod baz {
849 pub fn g() {}
850
851 pub mod qux {
852 pub fn h() {}
853 pub fn m() {}
854
855 pub mod q {
856 pub fn j() {}
857 }
858 }
859 }
860}
861
862use foo::{
863 bar::{*, f},
864 baz::{g, qux::{q::j, *$0}}
865};
866
867fn qux(bar: Bar, baz: Baz) {
868 f();
869 g();
870 h();
871 j();
872}
873",
874 r"
875mod foo {
876 pub mod bar {
877 pub struct Bar;
878 pub struct Baz;
879 pub struct Qux;
880
881 pub fn f() {}
882 }
883
884 pub mod baz {
885 pub fn g() {}
886
887 pub mod qux {
888 pub fn h() {}
889 pub fn m() {}
890
891 pub mod q {
892 pub fn j() {}
893 }
894 }
895 }
896}
897
898use foo::{
899 bar::{*, f},
900 baz::{g, qux::{q::j, h}}
901};
902
903fn qux(bar: Bar, baz: Baz) {
904 f();
905 g();
906 h();
907 j();
908}
909",
910 );
911 }
912
913 #[test]
914 fn expanding_glob_import_with_macro_defs() {
915 check_assist(
916 expand_glob_import,
917 r#"
918//- /lib.rs crate:foo
919#[macro_export]
920macro_rules! bar {
921 () => ()
922}
923
924pub fn baz() {}
925
926//- /main.rs crate:main deps:foo
927use foo::*$0;
928
929fn main() {
930 bar!();
931 baz();
932}
933"#,
934 r#"
935use foo::{bar, baz};
936
937fn main() {
938 bar!();
939 baz();
940}
941"#,
942 );
943 }
944
945 #[test]
946 fn expanding_glob_import_with_trait_method_uses() {
947 check_assist(
948 expand_glob_import,
949 r"
950//- /lib.rs crate:foo
951pub trait Tr {
952 fn method(&self) {}
953}
954impl Tr for () {}
955
956//- /main.rs crate:main deps:foo
957use foo::*$0;
958
959fn main() {
960 ().method();
961}
962",
963 r"
964use foo::Tr;
965
966fn main() {
967 ().method();
968}
969",
970 );
971
972 check_assist(
973 expand_glob_import,
974 r"
975//- /lib.rs crate:foo
976pub trait Tr {
977 fn method(&self) {}
978}
979impl Tr for () {}
980
981pub trait Tr2 {
982 fn method2(&self) {}
983}
984impl Tr2 for () {}
985
986//- /main.rs crate:main deps:foo
987use foo::*$0;
988
989fn main() {
990 ().method();
991}
992",
993 r"
994use foo::Tr;
995
996fn main() {
997 ().method();
998}
999",
1000 );
1001 }
1002
1003 #[test]
1004 fn expanding_is_not_applicable_if_target_module_is_not_accessible_from_current_scope() {
1005 check_assist_not_applicable(
1006 expand_glob_import,
1007 r"
1008mod foo {
1009 mod bar {
1010 pub struct Bar;
1011 }
1012}
1013
1014use foo::bar::*$0;
1015
1016fn baz(bar: Bar) {}
1017",
1018 );
1019
1020 check_assist_not_applicable(
1021 expand_glob_import,
1022 r"
1023mod foo {
1024 mod bar {
1025 pub mod baz {
1026 pub struct Baz;
1027 }
1028 }
1029}
1030
1031use foo::bar::baz::*$0;
1032
1033fn qux(baz: Baz) {}
1034",
1035 );
1036 }
1037
1038 #[test]
1039 fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() {
1040 check_assist_not_applicable(
1041 expand_glob_import,
1042 r"
1043 mod foo {
1044 pub struct Bar;
1045 pub struct Baz;
1046 pub struct Qux;
1047 }
1048
1049 use foo::Bar$0;
1050
1051 fn qux(bar: Bar, baz: Baz) {}
1052 ",
1053 )
1054 }
1055
1056 #[test]
1057 fn expanding_glob_import_single_nested_glob_only() {
1058 check_assist(
1059 expand_glob_import,
1060 r"
1061mod foo {
1062 pub struct Bar;
1063}
1064
1065use foo::{*$0};
1066
1067struct Baz {
1068 bar: Bar
1069}
1070",
1071 r"
1072mod foo {
1073 pub struct Bar;
1074}
1075
1076use foo::{Bar};
1077
1078struct Baz {
1079 bar: Bar
1080}
1081",
1082 );
1083 }
1084
1085 #[test]
1086 fn test_support_for_enums() {
1087 check_assist(
1088 expand_glob_import,
1089 r#"
1090mod foo {
1091 pub enum Foo {
1092 Bar,
1093 Baz,
1094 }
1095}
1096
1097use foo::Foo;
1098use foo::Foo::*$0;
1099
1100struct Strukt {
1101 bar: Foo,
1102}
1103
1104fn main() {
1105 let s: Strukt = Strukt { bar: Bar };
1106}"#,
1107 r#"
1108mod foo {
1109 pub enum Foo {
1110 Bar,
1111 Baz,
1112 }
1113}
1114
1115use foo::Foo;
1116use foo::Foo::Bar;
1117
1118struct Strukt {
1119 bar: Foo,
1120}
1121
1122fn main() {
1123 let s: Strukt = Strukt { bar: Bar };
1124}"#,
1125 )
1126 }
1127
1128 #[test]
1129 fn test_expanding_multiple_variants_at_once() {
1130 check_assist(
1131 expand_glob_import,
1132 r#"
1133mod foo {
1134 pub enum Foo {
1135 Bar,
1136 Baz,
1137 }
1138}
1139
1140mod abc {
1141 use super::foo;
1142 use super::foo::Foo::*$0;
1143
1144 struct Strukt {
1145 baz: foo::Foo,
1146 bar: foo::Foo,
1147 }
1148
1149 fn trying_calling() {
1150 let s: Strukt = Strukt { bar: Bar , baz : Baz };
1151 }
1152
1153}"#,
1154 r#"
1155mod foo {
1156 pub enum Foo {
1157 Bar,
1158 Baz,
1159 }
1160}
1161
1162mod abc {
1163 use super::foo;
1164 use super::foo::Foo::{Bar, Baz};
1165
1166 struct Strukt {
1167 baz: foo::Foo,
1168 bar: foo::Foo,
1169 }
1170
1171 fn trying_calling() {
1172 let s: Strukt = Strukt { bar: Bar , baz : Baz };
1173 }
1174
1175}"#,
1176 )
1177 }
1178
1179 #[test]
1180 fn expanding_glob_reexport() {
1181 check_assist(
1182 expand_glob_reexport,
1183 r"
1184mod foo {
1185 pub struct Bar;
1186 pub struct Baz;
1187 struct Qux;
1188
1189 pub fn f() {}
1190
1191 pub(crate) fn g() {}
1192 pub(self) fn h() {}
1193}
1194
1195pub use foo::*$0;
1196",
1197 r"
1198mod foo {
1199 pub struct Bar;
1200 pub struct Baz;
1201 struct Qux;
1202
1203 pub fn f() {}
1204
1205 pub(crate) fn g() {}
1206 pub(self) fn h() {}
1207}
1208
1209pub use foo::{Bar, Baz, f};
1210",
1211 )
1212 }
1213
1214 #[test]
1215 fn expanding_recursive_glob_reexport() {
1216 check_assist(
1217 expand_glob_reexport,
1218 r"
1219mod foo {
1220 pub use bar::*;
1221 mod bar {
1222 pub struct Bar;
1223 pub struct Baz;
1224 }
1225}
1226
1227pub use foo::*$0;
1228",
1229 r"
1230mod foo {
1231 pub use bar::*;
1232 mod bar {
1233 pub struct Bar;
1234 pub struct Baz;
1235 }
1236}
1237
1238pub use foo::{Bar, Baz};
1239",
1240 )
1241 }
1242
1243 #[test]
1244 fn expanding_reexport_is_not_applicable_for_private_import() {
1245 check_assist_not_applicable(
1246 expand_glob_reexport,
1247 r"
1248mod foo {
1249 pub struct Bar;
1250 pub struct Baz;
1251}
1252
1253use foo::*$0;
1254",
1255 );
1256 }
1257}