1- use hir:: { MacroDef , ModuleDef , Name , PathResolution , ScopeDef , SemanticsScope } ;
1+ use hir:: { AssocItem , MacroDef , ModuleDef , Name , PathResolution , ScopeDef , SemanticsScope } ;
22use ra_ide_db:: {
33 defs:: { classify_name_ref, Definition , NameRefClass } ,
44 RootDatabase ,
55} ;
6- use ra_syntax:: { ast, match_ast, AstNode , SyntaxNode , SyntaxToken , T } ;
6+ use ra_syntax:: { algo , ast, match_ast, AstNode , SyntaxNode , SyntaxToken , T } ;
77
88use crate :: {
99 assist_context:: { AssistBuilder , AssistContext , Assists } ,
1010 AssistId , AssistKind ,
1111} ;
1212
13+ use either:: Either ;
14+
1315// Assist: expand_glob_import
1416//
1517// Expands glob imports.
@@ -122,7 +124,19 @@ fn find_used_names(
122124
123125 defs_in_mod
124126 . iter ( )
125- . filter ( |d| defs_in_source_file. contains ( d) )
127+ . filter ( |def| {
128+ if let Def :: ModuleDef ( ModuleDef :: Trait ( tr) ) = def {
129+ for item in tr. items ( ctx. db ( ) ) {
130+ if let AssocItem :: Function ( f) = item {
131+ if defs_in_source_file. contains ( & Def :: ModuleDef ( ModuleDef :: Function ( f) ) ) {
132+ return true ;
133+ }
134+ }
135+ }
136+ }
137+
138+ defs_in_source_file. contains ( def)
139+ } )
126140 . filter_map ( |d| d. name ( ctx. db ( ) ) )
127141 . collect ( )
128142}
@@ -133,28 +147,38 @@ fn replace_ast(
133147 path : ast:: Path ,
134148 used_names : Vec < Name > ,
135149) {
136- let new_use_tree_list = ast:: make:: use_tree_list ( used_names. iter ( ) . map ( |n| {
137- ast:: make:: use_tree ( ast:: make:: path_from_text ( & n. to_string ( ) ) , None , None , false )
138- } ) ) ;
150+ let replacement: Either < ast:: UseTree , ast:: UseTreeList > = if used_names. len ( ) == 1 {
151+ Either :: Left ( ast:: make:: use_tree (
152+ ast:: make:: path_from_text ( & format ! ( "{}::{}" , path, used_names. first( ) . unwrap( ) ) ) ,
153+ None ,
154+ None ,
155+ false ,
156+ ) )
157+ } else {
158+ Either :: Right ( ast:: make:: use_tree_list ( used_names. iter ( ) . map ( |n| {
159+ ast:: make:: use_tree ( ast:: make:: path_from_text ( & n. to_string ( ) ) , None , None , false )
160+ } ) ) )
161+ } ;
162+
163+ let mut replace_node = |replacement : Either < ast:: UseTree , ast:: UseTreeList > | {
164+ algo:: diff ( node, & replacement. either ( |u| u. syntax ( ) . clone ( ) , |ut| ut. syntax ( ) . clone ( ) ) )
165+ . into_text_edit ( builder. text_edit_builder ( ) ) ;
166+ } ;
139167
140168 match_ast ! {
141169 match node {
142170 ast:: UseTree ( use_tree) => {
143- builder . replace_ast ( use_tree , make_use_tree ( path , new_use_tree_list ) ) ;
171+ replace_node ( replacement ) ;
144172 } ,
145173 ast:: UseTreeList ( use_tree_list) => {
146- builder . replace_ast ( use_tree_list , new_use_tree_list ) ;
174+ replace_node ( replacement ) ;
147175 } ,
148176 ast:: Use ( use_item) => {
149- builder. replace_ast( use_item, ast:: make:: use_item( make_use_tree ( path, new_use_tree_list ) ) ) ;
177+ builder. replace_ast( use_item, ast:: make:: use_item( replacement . left_or_else ( |ut| ast :: make :: use_tree ( path, Some ( ut ) , None , false ) ) ) ) ;
150178 } ,
151179 _ => { } ,
152180 }
153181 }
154-
155- fn make_use_tree ( path : ast:: Path , use_tree_list : ast:: UseTreeList ) -> ast:: UseTree {
156- ast:: make:: use_tree ( path, Some ( use_tree_list) , None , false )
157- }
158182}
159183
160184#[ cfg( test) ]
@@ -320,6 +344,34 @@ fn main() {
320344 )
321345 }
322346
347+ #[ test]
348+ fn expanding_glob_import_with_trait_method_uses ( ) {
349+ check_assist (
350+ expand_glob_import,
351+ r"
352+ //- /lib.rs crate:foo
353+ pub trait Tr {
354+ fn method(&self) {}
355+ }
356+ impl Tr for () {}
357+
358+ //- /main.rs crate:main deps:foo
359+ use foo::*<|>;
360+
361+ fn main() {
362+ ().method();
363+ }
364+ " ,
365+ r"
366+ use foo::Tr;
367+
368+ fn main() {
369+ ().method();
370+ }
371+ " ,
372+ )
373+ }
374+
323375 #[ test]
324376 fn expanding_is_not_applicable_if_cursor_is_not_in_star_token ( ) {
325377 check_assist_not_applicable (
0 commit comments