Skip to main content

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},
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 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            // We don't handle pub(in ...) and pub(super) yet
207            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    // could be alias
249    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
365// looks for name refs in parent use block's siblings
366//
367// mod bar {
368//     mod qux {
369//         struct Qux;
370//     }
371//
372//     pub use qux::Qux;
373// }
374//
375// ↓ ---------------
376// use foo::*$0;
377// use baz::Baz;
378// ↑ ---------------
379fn 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}