@@ -7,7 +7,7 @@ use ide_db::{
7
7
} ;
8
8
use stdx:: never;
9
9
use syntax:: {
10
- ast:: { self , make, Use , UseTree } ,
10
+ ast:: { self , make, Use , UseTree , VisibilityKind } ,
11
11
ted, AstNode , Direction , SyntaxNode , SyntaxToken , T ,
12
12
} ;
13
13
@@ -65,7 +65,76 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
65
65
"Expand glob import" ,
66
66
target. text_range ( ) ,
67
67
|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
+ )
69
138
} ,
70
139
)
71
140
}
@@ -77,13 +146,27 @@ fn build_expanded_import(
77
146
use_item : Use ,
78
147
target_module : Expandable ,
79
148
current_module : Module ,
149
+ reexport_public_items : bool ,
80
150
) {
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) ;
82
162
let imported_defs = find_imported_defs ( ctx, use_item) ;
83
163
164
+ let filtered_defs =
165
+ if reexport_public_items { refs_in_target } else { refs_in_target. used_refs ( ctx) } ;
166
+
84
167
let use_tree = builder. make_mut ( use_tree) ;
85
168
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) ;
87
170
let expanded = make:: use_tree_list ( names_to_import. iter ( ) . map ( |n| {
88
171
let path = make:: ext:: ident_path (
89
172
& n. display ( ctx. db ( ) , current_module. krate ( ) . edition ( ctx. db ( ) ) ) . to_string ( ) ,
@@ -110,6 +193,21 @@ fn build_expanded_import(
110
193
}
111
194
}
112
195
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
+
113
211
enum Expandable {
114
212
Module ( Module ) ,
115
213
Enum ( Enum ) ,
@@ -147,14 +245,17 @@ struct Ref {
147
245
// could be alias
148
246
visible_name : Name ,
149
247
def : Definition ,
248
+ is_pub : bool ,
150
249
}
151
250
152
251
impl 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 > {
154
253
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
+ } ) ,
158
259
_ => None ,
159
260
}
160
261
}
@@ -193,18 +294,30 @@ impl Refs {
193
294
}
194
295
}
195
296
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 {
197
303
match expandable {
198
304
Expandable :: Module ( module) => {
199
305
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 ( ) ;
202
311
Refs ( refs)
203
312
}
204
313
Expandable :: Enum ( enm) => Refs (
205
314
enm. variants ( ctx. db ( ) )
206
315
. 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
+ } )
208
321
. collect ( ) ,
209
322
) ,
210
323
}
@@ -276,13 +389,9 @@ fn find_imported_defs(ctx: &AssistContext<'_>, use_item: Use) -> Vec<Definition>
276
389
. collect ( )
277
390
}
278
391
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 ( )
286
395
}
287
396
288
397
#[ cfg( test) ]
@@ -1029,4 +1138,83 @@ mod abc {
1029
1138
}"# ,
1030
1139
)
1031
1140
}
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
+ }
1032
1220
}
0 commit comments