@@ -5,14 +5,16 @@ use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
55use fst:: { self , Streamer } ;
66use indexmap:: { map:: Entry , IndexMap } ;
77use ra_db:: CrateId ;
8- use rustc_hash:: FxHasher ;
8+ use ra_syntax:: SmolStr ;
9+ use rustc_hash:: { FxHashMap , FxHasher } ;
10+ use smallvec:: SmallVec ;
911
1012use crate :: {
1113 db:: DefDatabase ,
1214 item_scope:: ItemInNs ,
1315 path:: { ModPath , PathKind } ,
1416 visibility:: Visibility ,
15- ModuleDefId , ModuleId ,
17+ AssocItemId , ModuleDefId , ModuleId , TraitId ,
1618} ;
1719
1820type FxIndexMap < K , V > = IndexMap < K , V , BuildHasherDefault < FxHasher > > ;
@@ -34,6 +36,7 @@ pub struct ImportInfo {
3436///
3537/// Note that all paths are relative to the containing crate's root, so the crate name still needs
3638/// to be prepended to the `ModPath` before the path is valid.
39+ #[ derive( Default ) ]
3740pub struct ImportMap {
3841 map : FxIndexMap < ItemInNs , ImportInfo > ,
3942
@@ -45,13 +48,17 @@ pub struct ImportMap {
4548 /// the index of the first one.
4649 importables : Vec < ItemInNs > ,
4750 fst : fst:: Map < Vec < u8 > > ,
51+
52+ /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
53+ /// exported.
54+ assoc_map : FxHashMap < SmolStr , SmallVec < [ AssocItemId ; 1 ] > > ,
4855}
4956
5057impl ImportMap {
5158 pub fn import_map_query ( db : & dyn DefDatabase , krate : CrateId ) -> Arc < Self > {
5259 let _p = ra_prof:: profile ( "import_map_query" ) ;
5360 let def_map = db. crate_def_map ( krate) ;
54- let mut import_map = FxIndexMap :: with_capacity_and_hasher ( 64 , Default :: default ( ) ) ;
61+ let mut import_map = Self :: default ( ) ;
5562
5663 // We look only into modules that are public(ly reexported), starting with the crate root.
5764 let empty = ModPath { kind : PathKind :: Plain , segments : vec ! [ ] } ;
@@ -85,7 +92,7 @@ impl ImportMap {
8592
8693 for item in per_ns. iter_items ( ) {
8794 let path = mk_path ( ) ;
88- match import_map. entry ( item) {
95+ match import_map. map . entry ( item) {
8996 Entry :: Vacant ( entry) => {
9097 entry. insert ( ImportInfo { path, container : module } ) ;
9198 }
@@ -105,11 +112,16 @@ impl ImportMap {
105112 if let Some ( ModuleDefId :: ModuleId ( mod_id) ) = item. as_module_def_id ( ) {
106113 worklist. push ( ( mod_id, mk_path ( ) ) ) ;
107114 }
115+
116+ // If we've added a path to a trait, add the trait's methods to the method map.
117+ if let Some ( ModuleDefId :: TraitId ( tr) ) = item. as_module_def_id ( ) {
118+ import_map. collect_trait_methods ( db, tr) ;
119+ }
108120 }
109121 }
110122 }
111123
112- let mut importables = import_map. iter ( ) . collect :: < Vec < _ > > ( ) ;
124+ let mut importables = import_map. map . iter ( ) . collect :: < Vec < _ > > ( ) ;
113125
114126 importables. sort_by ( cmp) ;
115127
@@ -133,10 +145,10 @@ impl ImportMap {
133145 builder. insert ( key, start as u64 ) . unwrap ( ) ;
134146 }
135147
136- let fst = fst:: Map :: new ( builder. into_inner ( ) . unwrap ( ) ) . unwrap ( ) ;
137- let importables = importables. iter ( ) . map ( |( item, _) | * * item) . collect ( ) ;
148+ import_map . fst = fst:: Map :: new ( builder. into_inner ( ) . unwrap ( ) ) . unwrap ( ) ;
149+ import_map . importables = importables. iter ( ) . map ( |( item, _) | * * item) . collect ( ) ;
138150
139- Arc :: new ( Self { map : import_map, fst , importables } )
151+ Arc :: new ( import_map)
140152 }
141153
142154 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
@@ -147,6 +159,13 @@ impl ImportMap {
147159 pub fn import_info_for ( & self , item : ItemInNs ) -> Option < & ImportInfo > {
148160 self . map . get ( & item)
149161 }
162+
163+ fn collect_trait_methods ( & mut self , db : & dyn DefDatabase , tr : TraitId ) {
164+ let data = db. trait_data ( tr) ;
165+ for ( name, item) in data. items . iter ( ) {
166+ self . assoc_map . entry ( name. to_string ( ) . into ( ) ) . or_default ( ) . push ( * item) ;
167+ }
168+ }
150169}
151170
152171impl PartialEq for ImportMap {
@@ -290,13 +309,26 @@ pub fn search_dependencies<'a>(
290309 }
291310 }
292311
312+ // Add all exported associated items whose names match the query (exactly).
313+ for map in & import_maps {
314+ if let Some ( v) = map. assoc_map . get ( & * query. query ) {
315+ res. extend ( v. iter ( ) . map ( |& assoc| {
316+ ItemInNs :: Types ( match assoc {
317+ AssocItemId :: FunctionId ( it) => it. into ( ) ,
318+ AssocItemId :: ConstId ( it) => it. into ( ) ,
319+ AssocItemId :: TypeAliasId ( it) => it. into ( ) ,
320+ } )
321+ } ) ) ;
322+ }
323+ }
324+
293325 res
294326}
295327
296328#[ cfg( test) ]
297329mod tests {
298330 use super :: * ;
299- use crate :: test_db:: TestDB ;
331+ use crate :: { test_db:: TestDB , AssocContainerId , Lookup } ;
300332 use insta:: assert_snapshot;
301333 use itertools:: Itertools ;
302334 use ra_db:: fixture:: WithFixture ;
@@ -339,6 +371,7 @@ mod tests {
339371 ItemInNs :: Values ( _) => "v" ,
340372 ItemInNs :: Macros ( _) => "m" ,
341373 } ;
374+ let item = assoc_to_trait ( & db, item) ;
342375 item. krate ( db. upcast ( ) ) . map ( |krate| {
343376 let map = db. import_map ( krate) ;
344377 let path = map. path_of ( item) . unwrap ( ) ;
@@ -353,6 +386,29 @@ mod tests {
353386 . join ( "\n " )
354387 }
355388
389+ fn assoc_to_trait ( db : & dyn DefDatabase , item : ItemInNs ) -> ItemInNs {
390+ let assoc: AssocItemId = match item {
391+ ItemInNs :: Types ( it) | ItemInNs :: Values ( it) => match it {
392+ ModuleDefId :: TypeAliasId ( it) => it. into ( ) ,
393+ ModuleDefId :: FunctionId ( it) => it. into ( ) ,
394+ ModuleDefId :: ConstId ( it) => it. into ( ) ,
395+ _ => return item,
396+ } ,
397+ _ => return item,
398+ } ;
399+
400+ let container = match assoc {
401+ AssocItemId :: FunctionId ( it) => it. lookup ( db) . container ,
402+ AssocItemId :: ConstId ( it) => it. lookup ( db) . container ,
403+ AssocItemId :: TypeAliasId ( it) => it. lookup ( db) . container ,
404+ } ;
405+
406+ match container {
407+ AssocContainerId :: TraitId ( it) => ItemInNs :: Types ( it. into ( ) ) ,
408+ _ => item,
409+ }
410+ }
411+
356412 #[ test]
357413 fn smoke ( ) {
358414 let map = import_map (
@@ -610,6 +666,7 @@ mod tests {
610666 dep::Fmt (m)
611667 dep::fmt::Display (t)
612668 dep::format (v)
669+ dep::fmt::Display (t)
613670 "### ) ;
614671
615672 let res = search_dependencies_of ( ra_fixture, "main" , Query :: new ( "fmt" ) . anchor_end ( ) ) ;
@@ -618,6 +675,7 @@ mod tests {
618675 dep::Fmt (t)
619676 dep::Fmt (v)
620677 dep::Fmt (m)
678+ dep::fmt::Display (t)
621679 "### ) ;
622680 }
623681
0 commit comments