@@ -7,7 +7,7 @@ use ide_db::{
77} ;
88use stdx:: never;
99use syntax:: {
10- ast:: { self , make, Use , UseTree } ,
10+ ast:: { self , make, Use , UseTree , VisibilityKind } ,
1111 ted, AstNode , Direction , SyntaxNode , SyntaxToken , T ,
1212} ;
1313
@@ -65,7 +65,76 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
6565 "Expand glob import" ,
6666 target. text_range ( ) ,
6767 |builder| {
68- build_expanded_import ( ctx, builder, use_tree, use_item, target_module, current_module)
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+ // ```
102+ pub ( 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 ( "expand_glob_reexport" , AssistKind :: RefactorRewrite ) ,
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+ )
69138 } ,
70139 )
71140}
@@ -77,13 +146,27 @@ fn build_expanded_import(
77146 use_item : Use ,
78147 target_module : Expandable ,
79148 current_module : Module ,
149+ reexport_public_items : bool ,
80150) {
81- let refs_in_target = find_refs_in_mod ( ctx, target_module, current_module) ;
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 ( ) . root_module ( ) ) ,
156+ VisibilityKind :: PubCrate => ( false , current_module. krate ( ) . root_module ( ) ) ,
157+ _ => ( false , current_module) ,
158+ }
159+ } ;
160+
161+ let refs_in_target = find_refs_in_mod ( ctx, target_module, visible_from, must_be_pub) ;
82162 let imported_defs = find_imported_defs ( ctx, use_item) ;
83163
164+ let filtered_defs =
165+ if reexport_public_items { refs_in_target } else { refs_in_target. used_refs ( ctx) } ;
166+
84167 let use_tree = builder. make_mut ( use_tree) ;
85168
86- let names_to_import = find_names_to_import ( ctx , refs_in_target , imported_defs) ;
169+ let names_to_import = find_names_to_import ( filtered_defs , imported_defs) ;
87170 let expanded = make:: use_tree_list ( names_to_import. iter ( ) . map ( |n| {
88171 let path = make:: ext:: ident_path (
89172 & n. display ( ctx. db ( ) , current_module. krate ( ) . edition ( ctx. db ( ) ) ) . to_string ( ) ,
@@ -110,6 +193,21 @@ fn build_expanded_import(
110193 }
111194}
112195
196+ fn get_export_visibility_kind ( use_item : & Use ) -> VisibilityKind {
197+ use syntax:: ast:: HasVisibility as _;
198+ match use_item. visibility ( ) {
199+ Some ( vis) => match vis. kind ( ) {
200+ VisibilityKind :: PubCrate => VisibilityKind :: PubCrate ,
201+ VisibilityKind :: Pub => VisibilityKind :: Pub ,
202+ VisibilityKind :: PubSelf => VisibilityKind :: PubSelf ,
203+ // We don't handle pub(in ...) and pub(super) yet
204+ VisibilityKind :: In ( _) => VisibilityKind :: PubSelf ,
205+ VisibilityKind :: PubSuper => VisibilityKind :: PubSelf ,
206+ } ,
207+ None => VisibilityKind :: PubSelf ,
208+ }
209+ }
210+
113211enum Expandable {
114212 Module ( Module ) ,
115213 Enum ( Enum ) ,
@@ -147,14 +245,17 @@ struct Ref {
147245 // could be alias
148246 visible_name : Name ,
149247 def : Definition ,
248+ is_pub : bool ,
150249}
151250
152251impl Ref {
153- fn from_scope_def ( name : Name , scope_def : ScopeDef ) -> Option < Self > {
252+ fn from_scope_def ( ctx : & AssistContext < ' _ > , name : Name , scope_def : ScopeDef ) -> Option < Self > {
154253 match scope_def {
155- ScopeDef :: ModuleDef ( def) => {
156- Some ( Ref { visible_name : name, def : Definition :: from ( def) } )
157- }
254+ ScopeDef :: ModuleDef ( def) => Some ( Ref {
255+ visible_name : name,
256+ def : Definition :: from ( def) ,
257+ is_pub : matches ! ( def. visibility( ctx. db( ) ) , hir:: Visibility :: Public ) ,
258+ } ) ,
158259 _ => None ,
159260 }
160261 }
@@ -193,18 +294,30 @@ impl Refs {
193294 }
194295}
195296
196- fn find_refs_in_mod ( ctx : & AssistContext < ' _ > , expandable : Expandable , visible_from : Module ) -> Refs {
297+ fn find_refs_in_mod (
298+ ctx : & AssistContext < ' _ > ,
299+ expandable : Expandable ,
300+ visible_from : Module ,
301+ must_be_pub : bool ,
302+ ) -> Refs {
197303 match expandable {
198304 Expandable :: Module ( module) => {
199305 let module_scope = module. scope ( ctx. db ( ) , Some ( visible_from) ) ;
200- let refs =
201- module_scope. into_iter ( ) . filter_map ( |( n, d) | Ref :: from_scope_def ( n, d) ) . collect ( ) ;
306+ let refs = module_scope
307+ . into_iter ( )
308+ . filter_map ( |( n, d) | Ref :: from_scope_def ( ctx, n, d) )
309+ . filter ( |r| !must_be_pub || r. is_pub )
310+ . collect ( ) ;
202311 Refs ( refs)
203312 }
204313 Expandable :: Enum ( enm) => Refs (
205314 enm. variants ( ctx. db ( ) )
206315 . into_iter ( )
207- . map ( |v| Ref { visible_name : v. name ( ctx. db ( ) ) , def : Definition :: Variant ( v) } )
316+ . map ( |v| Ref {
317+ visible_name : v. name ( ctx. db ( ) ) ,
318+ def : Definition :: Variant ( v) ,
319+ is_pub : true ,
320+ } )
208321 . collect ( ) ,
209322 ) ,
210323 }
@@ -276,13 +389,9 @@ fn find_imported_defs(ctx: &AssistContext<'_>, use_item: Use) -> Vec<Definition>
276389 . collect ( )
277390}
278391
279- fn find_names_to_import (
280- ctx : & AssistContext < ' _ > ,
281- refs_in_target : Refs ,
282- imported_defs : Vec < Definition > ,
283- ) -> Vec < Name > {
284- let used_refs = refs_in_target. used_refs ( ctx) . filter_out_by_defs ( imported_defs) ;
285- used_refs. 0 . iter ( ) . map ( |r| r. visible_name . clone ( ) ) . collect ( )
392+ fn find_names_to_import ( refs_in_target : Refs , imported_defs : Vec < Definition > ) -> Vec < Name > {
393+ let final_refs = refs_in_target. filter_out_by_defs ( imported_defs) ;
394+ final_refs. 0 . iter ( ) . map ( |r| r. visible_name . clone ( ) ) . collect ( )
286395}
287396
288397#[ cfg( test) ]
@@ -1029,4 +1138,83 @@ mod abc {
10291138}"# ,
10301139 )
10311140 }
1141+
1142+ #[ test]
1143+ fn expanding_glob_reexport ( ) {
1144+ check_assist (
1145+ expand_glob_reexport,
1146+ r"
1147+ mod foo {
1148+ pub struct Bar;
1149+ pub struct Baz;
1150+ struct Qux;
1151+
1152+ pub fn f() {}
1153+
1154+ pub(crate) fn g() {}
1155+ pub(self) fn h() {}
1156+ }
1157+
1158+ pub use foo::*$0;
1159+ " ,
1160+ r"
1161+ mod foo {
1162+ pub struct Bar;
1163+ pub struct Baz;
1164+ struct Qux;
1165+
1166+ pub fn f() {}
1167+
1168+ pub(crate) fn g() {}
1169+ pub(self) fn h() {}
1170+ }
1171+
1172+ pub use foo::{Bar, Baz, f};
1173+ " ,
1174+ )
1175+ }
1176+
1177+ #[ test]
1178+ fn expanding_recursive_glob_reexport ( ) {
1179+ check_assist (
1180+ expand_glob_reexport,
1181+ r"
1182+ mod foo {
1183+ pub use bar::*;
1184+ mod bar {
1185+ pub struct Bar;
1186+ pub struct Baz;
1187+ }
1188+ }
1189+
1190+ pub use foo::*$0;
1191+ " ,
1192+ r"
1193+ mod foo {
1194+ pub use bar::*;
1195+ mod bar {
1196+ pub struct Bar;
1197+ pub struct Baz;
1198+ }
1199+ }
1200+
1201+ pub use foo::{Bar, Baz};
1202+ " ,
1203+ )
1204+ }
1205+
1206+ #[ test]
1207+ fn expanding_reexport_is_not_applicable_for_private_import ( ) {
1208+ check_assist_not_applicable (
1209+ expand_glob_reexport,
1210+ r"
1211+ mod foo {
1212+ pub struct Bar;
1213+ pub struct Baz;
1214+ }
1215+
1216+ use foo::*$0;
1217+ " ,
1218+ ) ;
1219+ }
10321220}
0 commit comments