ide_assists/handlers/
expand_glob_import.rs

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