@@ -5,7 +5,13 @@ use crate::{
55 assist_ctx:: { Assist , AssistCtx } ,
66 insert_use_statement, AssistId ,
77} ;
8- use hir:: { db:: HirDatabase , Adt , ModPath , Module , ModuleDef , PathResolution , SourceAnalyzer } ;
8+ use ast:: { FnDefOwner , ModuleItem , ModuleItemOwner } ;
9+ use hir:: {
10+ db:: { DefDatabase , HirDatabase } ,
11+ Adt , AssocContainerId , Crate , Function , HasSource , InFile , ModPath , Module , ModuleDef ,
12+ PathResolution , SourceAnalyzer , SourceBinder , Trait ,
13+ } ;
14+ use rustc_hash:: FxHashSet ;
915use std:: collections:: BTreeSet ;
1016
1117// Assist: auto_import
@@ -135,21 +141,88 @@ impl ImportCandidate {
135141 ImportsLocator :: new ( db)
136142 . find_imports ( & self . get_search_query ( ) )
137143 . into_iter ( )
138- . filter_map ( |module_def| match self {
144+ . map ( |module_def| match self {
139145 ImportCandidate :: TraitFunction ( function_callee, _) => {
140- if let ModuleDef :: Function ( function) = module_def {
141- dbg ! ( function) ;
142- todo ! ( )
143- } else {
144- None
146+ let mut applicable_traits = Vec :: new ( ) ;
147+ if let ModuleDef :: Function ( located_function) = module_def {
148+ let trait_candidates = Self :: get_trait_candidates (
149+ db,
150+ located_function,
151+ module_with_name_to_import. krate ( ) ,
152+ )
153+ . into_iter ( )
154+ . map ( |trait_candidate| trait_candidate. into ( ) )
155+ . collect ( ) ;
156+
157+ function_callee. ty ( db) . iterate_path_candidates (
158+ db,
159+ module_with_name_to_import. krate ( ) ,
160+ & trait_candidates,
161+ None ,
162+ |_, assoc| {
163+ if let AssocContainerId :: TraitId ( trait_id) = assoc. container ( db) {
164+ applicable_traits. push (
165+ module_with_name_to_import
166+ . find_use_path ( db, ModuleDef :: Trait ( trait_id. into ( ) ) ) ,
167+ ) ;
168+ } ;
169+ None :: < ( ) >
170+ } ,
171+ ) ;
145172 }
173+ applicable_traits
146174 }
147- _ => module_with_name_to_import. find_use_path ( db, module_def) ,
175+ _ => vec ! [ module_with_name_to_import. find_use_path( db, module_def) ] ,
148176 } )
177+ . flatten ( )
178+ . filter_map ( std:: convert:: identity)
149179 . filter ( |use_path| !use_path. segments . is_empty ( ) )
150180 . take ( 20 )
151181 . collect :: < BTreeSet < _ > > ( )
152182 }
183+
184+ fn get_trait_candidates (
185+ db : & RootDatabase ,
186+ called_function : Function ,
187+ root_crate : Crate ,
188+ ) -> FxHashSet < Trait > {
189+ let mut source_binder = SourceBinder :: new ( db) ;
190+ root_crate
191+ . dependencies ( db)
192+ . into_iter ( )
193+ . map ( |dependency| db. crate_def_map ( dependency. krate . into ( ) ) )
194+ . chain ( std:: iter:: once ( db. crate_def_map ( root_crate. into ( ) ) ) )
195+ . map ( |crate_def_map| {
196+ crate_def_map
197+ . modules
198+ . iter ( )
199+ . filter_map ( |( _, module_data) | module_data. declaration_source ( db) )
200+ . filter_map ( |in_file_module| {
201+ Some ( ( in_file_module. file_id , in_file_module. value . item_list ( ) ?. items ( ) ) )
202+ } )
203+ . map ( |( file_id, item_list) | {
204+ let mut if_file_trait_defs = Vec :: new ( ) ;
205+ for module_item in item_list {
206+ if let ModuleItem :: TraitDef ( trait_def) = module_item {
207+ if let Some ( item_list) = trait_def. item_list ( ) {
208+ if item_list
209+ . functions ( )
210+ . any ( |fn_def| fn_def == called_function. source ( db) . value )
211+ {
212+ if_file_trait_defs. push ( InFile :: new ( file_id, trait_def) )
213+ }
214+ }
215+ }
216+ }
217+ if_file_trait_defs
218+ } )
219+ . flatten ( )
220+ . filter_map ( |in_file_trait_def| source_binder. to_def ( in_file_trait_def) )
221+ . collect :: < FxHashSet < _ > > ( )
222+ } )
223+ . flatten ( )
224+ . collect ( )
225+ }
153226}
154227
155228#[ cfg( test) ]
@@ -452,7 +525,45 @@ mod tests {
452525 }
453526
454527 #[ test]
455- #[ ignore] // TODO kb
528+ fn not_applicable_for_imported_trait ( ) {
529+ check_assist_not_applicable (
530+ auto_import,
531+ r"
532+ mod test_mod {
533+ pub trait TestTrait {
534+ fn test_method(&self);
535+ fn test_function();
536+ }
537+
538+ pub trait TestTrait2 {
539+ fn test_method(&self);
540+ fn test_function();
541+ }
542+ pub enum TestEnum {
543+ One,
544+ Two,
545+ }
546+
547+ impl TestTrait2 for TestEnum {
548+ fn test_method(&self) {}
549+ fn test_function() {}
550+ }
551+
552+ impl TestTrait for TestEnum {
553+ fn test_method(&self) {}
554+ fn test_function() {}
555+ }
556+ }
557+
558+ use test_mod::TestTrait2;
559+ fn main() {
560+ test_mod::TestEnum::test_function<|>;
561+ }
562+ " ,
563+ )
564+ }
565+
566+ #[ test]
456567 fn trait_method ( ) {
457568 check_assist (
458569 auto_import,
0 commit comments