@@ -3,10 +3,11 @@ use hir::{AssocItem, Enum, HasVisibility, Module, ModuleDef, Name, PathResolutio
33use ide_db:: {
44 defs:: { Definition , NameRefClass } ,
55 search:: SearchScope ,
6+ source_change:: SourceChangeBuilder ,
67} ;
78use stdx:: never;
89use syntax:: {
9- ast:: { self , make} ,
10+ ast:: { self , make, Use , UseTree } ,
1011 ted, AstNode , Direction , SyntaxNode , SyntaxToken , T ,
1112} ;
1213
@@ -43,6 +44,7 @@ use crate::{
4344pub ( crate ) fn expand_glob_import ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
4445 let star = ctx. find_token_syntax_at_offset ( T ! [ * ] ) ?;
4546 let use_tree = star. parent ( ) . and_then ( ast:: UseTree :: cast) ?;
47+ let use_item = star. parent_ancestors ( ) . find_map ( ast:: Use :: cast) ?;
4648 let ( parent, mod_path) = find_parent_and_path ( & star) ?;
4749 let target_module = match ctx. sema . resolve_path ( & mod_path) ? {
4850 PathResolution :: Def ( ModuleDef :: Module ( it) ) => Expandable :: Module ( it) ,
@@ -53,46 +55,61 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) ->
5355 let current_scope = ctx. sema . scope ( & star. parent ( ) ?) ?;
5456 let current_module = current_scope. module ( ) ;
5557
56- let refs_in_target = find_refs_in_mod ( ctx, target_module, current_module) ?;
57- let imported_defs = find_imported_defs ( ctx, star) ?;
58+ if !is_visible_from ( ctx, & target_module, current_module) {
59+ return None ;
60+ }
5861
5962 let target = parent. either ( |n| n. syntax ( ) . clone ( ) , |n| n. syntax ( ) . clone ( ) ) ;
6063 acc. add (
6164 AssistId ( "expand_glob_import" , AssistKind :: RefactorRewrite ) ,
6265 "Expand glob import" ,
6366 target. text_range ( ) ,
6467 |builder| {
65- let use_tree = builder. make_mut ( use_tree) ;
66-
67- let names_to_import = find_names_to_import ( ctx, refs_in_target, imported_defs) ;
68- let expanded = make:: use_tree_list ( names_to_import. iter ( ) . map ( |n| {
69- let path = make:: ext:: ident_path (
70- & n. display ( ctx. db ( ) , current_module. krate ( ) . edition ( ctx. db ( ) ) ) . to_string ( ) ,
71- ) ;
72- make:: use_tree ( path, None , None , false )
73- } ) )
74- . clone_for_update ( ) ;
75-
76- match use_tree. star_token ( ) {
77- Some ( star) => {
78- let needs_braces = use_tree. path ( ) . is_some ( ) && names_to_import. len ( ) != 1 ;
79- if needs_braces {
80- ted:: replace ( star, expanded. syntax ( ) )
81- } else {
82- let without_braces = expanded
83- . syntax ( )
84- . children_with_tokens ( )
85- . filter ( |child| !matches ! ( child. kind( ) , T ![ '{' ] | T ![ '}' ] ) )
86- . collect ( ) ;
87- ted:: replace_with_many ( star, without_braces)
88- }
89- }
90- None => never ! ( ) ,
91- }
68+ build_expanded_import ( ctx, builder, use_tree, use_item, target_module, current_module)
9269 } ,
9370 )
9471}
9572
73+ fn build_expanded_import (
74+ ctx : & AssistContext < ' _ > ,
75+ builder : & mut SourceChangeBuilder ,
76+ use_tree : UseTree ,
77+ use_item : Use ,
78+ target_module : Expandable ,
79+ current_module : Module ,
80+ ) {
81+ let refs_in_target = find_refs_in_mod ( ctx, target_module, current_module) ;
82+ let imported_defs = find_imported_defs ( ctx, use_item) ;
83+
84+ let use_tree = builder. make_mut ( use_tree) ;
85+
86+ let names_to_import = find_names_to_import ( ctx, refs_in_target, imported_defs) ;
87+ let expanded = make:: use_tree_list ( names_to_import. iter ( ) . map ( |n| {
88+ let path = make:: ext:: ident_path (
89+ & n. display ( ctx. db ( ) , current_module. krate ( ) . edition ( ctx. db ( ) ) ) . to_string ( ) ,
90+ ) ;
91+ make:: use_tree ( path, None , None , false )
92+ } ) )
93+ . clone_for_update ( ) ;
94+
95+ match use_tree. star_token ( ) {
96+ Some ( star) => {
97+ let needs_braces = use_tree. path ( ) . is_some ( ) && names_to_import. len ( ) != 1 ;
98+ if needs_braces {
99+ ted:: replace ( star, expanded. syntax ( ) )
100+ } else {
101+ let without_braces = expanded
102+ . syntax ( )
103+ . children_with_tokens ( )
104+ . filter ( |child| !matches ! ( child. kind( ) , T ![ '{' ] | T ![ '}' ] ) )
105+ . collect ( ) ;
106+ ted:: replace_with_many ( star, without_braces)
107+ }
108+ }
109+ None => never ! ( ) ,
110+ }
111+ }
112+
96113enum Expandable {
97114 Module ( Module ) ,
98115 Enum ( Enum ) ,
@@ -176,36 +193,24 @@ impl Refs {
176193 }
177194}
178195
179- fn find_refs_in_mod (
180- ctx : & AssistContext < ' _ > ,
181- expandable : Expandable ,
182- visible_from : Module ,
183- ) -> Option < Refs > {
184- if !is_expandable_visible_from ( ctx, & expandable, visible_from) {
185- return None ;
186- }
187-
196+ fn find_refs_in_mod ( ctx : & AssistContext < ' _ > , expandable : Expandable , visible_from : Module ) -> Refs {
188197 match expandable {
189198 Expandable :: Module ( module) => {
190199 let module_scope = module. scope ( ctx. db ( ) , Some ( visible_from) ) ;
191200 let refs =
192201 module_scope. into_iter ( ) . filter_map ( |( n, d) | Ref :: from_scope_def ( n, d) ) . collect ( ) ;
193- Some ( Refs ( refs) )
202+ Refs ( refs)
194203 }
195- Expandable :: Enum ( enm) => Some ( Refs (
204+ Expandable :: Enum ( enm) => Refs (
196205 enm. variants ( ctx. db ( ) )
197206 . into_iter ( )
198207 . map ( |v| Ref { visible_name : v. name ( ctx. db ( ) ) , def : Definition :: Variant ( v) } )
199208 . collect ( ) ,
200- ) ) ,
209+ ) ,
201210 }
202211}
203212
204- fn is_expandable_visible_from (
205- ctx : & AssistContext < ' _ > ,
206- expandable : & Expandable ,
207- from : Module ,
208- ) -> bool {
213+ fn is_visible_from ( ctx : & AssistContext < ' _ > , expandable : & Expandable , from : Module ) -> bool {
209214 fn is_mod_visible_from ( ctx : & AssistContext < ' _ > , module : Module , from : Module ) -> bool {
210215 match module. parent ( ctx. db ( ) ) {
211216 Some ( parent) => {
@@ -246,41 +251,29 @@ fn is_expandable_visible_from(
246251// use foo::*$0;
247252// use baz::Baz;
248253// ↑ ---------------
249- fn find_imported_defs ( ctx : & AssistContext < ' _ > , star : SyntaxToken ) -> Option < Vec < Definition > > {
250- let parent_use_item_syntax = star. parent_ancestors ( ) . find_map ( |n| {
251- if ast:: Use :: can_cast ( n. kind ( ) ) {
252- Some ( n)
253- } else {
254- None
255- }
256- } ) ?;
257-
258- Some (
259- [ Direction :: Prev , Direction :: Next ]
260- . into_iter ( )
261- . flat_map ( |dir| {
262- parent_use_item_syntax
263- . siblings ( dir. to_owned ( ) )
264- . filter ( |n| ast:: Use :: can_cast ( n. kind ( ) ) )
265- } )
266- . flat_map ( |n| n. descendants ( ) . filter_map ( ast:: NameRef :: cast) )
267- . filter_map ( |r| match NameRefClass :: classify ( & ctx. sema , & r) ? {
268- NameRefClass :: Definition (
269- def @ ( Definition :: Macro ( _)
270- | Definition :: Module ( _)
271- | Definition :: Function ( _)
272- | Definition :: Adt ( _)
273- | Definition :: Variant ( _)
274- | Definition :: Const ( _)
275- | Definition :: Static ( _)
276- | Definition :: Trait ( _)
277- | Definition :: TypeAlias ( _) ) ,
278- _,
279- ) => Some ( def) ,
280- _ => None ,
281- } )
282- . collect ( ) ,
283- )
254+ fn find_imported_defs ( ctx : & AssistContext < ' _ > , use_item : Use ) -> Vec < Definition > {
255+ [ Direction :: Prev , Direction :: Next ]
256+ . into_iter ( )
257+ . flat_map ( |dir| {
258+ use_item. syntax ( ) . siblings ( dir. to_owned ( ) ) . filter ( |n| ast:: Use :: can_cast ( n. kind ( ) ) )
259+ } )
260+ . flat_map ( |n| n. descendants ( ) . filter_map ( ast:: NameRef :: cast) )
261+ . filter_map ( |r| match NameRefClass :: classify ( & ctx. sema , & r) ? {
262+ NameRefClass :: Definition (
263+ def @ ( Definition :: Macro ( _)
264+ | Definition :: Module ( _)
265+ | Definition :: Function ( _)
266+ | Definition :: Adt ( _)
267+ | Definition :: Variant ( _)
268+ | Definition :: Const ( _)
269+ | Definition :: Static ( _)
270+ | Definition :: Trait ( _)
271+ | Definition :: TypeAlias ( _) ) ,
272+ _,
273+ ) => Some ( def) ,
274+ _ => None ,
275+ } )
276+ . collect ( )
284277}
285278
286279fn find_names_to_import (
0 commit comments