@@ -4,12 +4,11 @@ use crate::{
4
4
db:: DefDatabase ,
5
5
item_scope:: ItemInNs ,
6
6
path:: { ModPath , PathKind } ,
7
- ModuleId , ModuleDefId ,
7
+ visibility:: Visibility ,
8
+ CrateId , ModuleDefId , ModuleId ,
8
9
} ;
9
10
use hir_expand:: name:: Name ;
10
11
11
- // TODO performance / memoize
12
-
13
12
pub fn find_path ( db : & impl DefDatabase , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
14
13
// Base cases:
15
14
@@ -21,13 +20,23 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
21
20
}
22
21
23
22
// - if the item is the crate root, return `crate`
24
- if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( ModuleId { krate : from. krate , local_id : def_map. root } ) ) {
23
+ if item
24
+ == ItemInNs :: Types ( ModuleDefId :: ModuleId ( ModuleId {
25
+ krate : from. krate ,
26
+ local_id : def_map. root ,
27
+ } ) )
28
+ {
25
29
return Some ( ModPath :: from_simple_segments ( PathKind :: Crate , Vec :: new ( ) ) ) ;
26
30
}
27
31
28
32
// - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
29
33
if let Some ( parent_id) = def_map. modules [ from. local_id ] . parent {
30
- if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( ModuleId { krate : from. krate , local_id : parent_id } ) ) {
34
+ if item
35
+ == ItemInNs :: Types ( ModuleDefId :: ModuleId ( ModuleId {
36
+ krate : from. krate ,
37
+ local_id : parent_id,
38
+ } ) )
39
+ {
31
40
return Some ( ModPath :: from_simple_segments ( PathKind :: Super ( 1 ) , Vec :: new ( ) ) ) ;
32
41
}
33
42
}
@@ -42,7 +51,8 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
42
51
// - if the item is in the prelude, return the name from there
43
52
if let Some ( prelude_module) = def_map. prelude {
44
53
let prelude_def_map = db. crate_def_map ( prelude_module. krate ) ;
45
- let prelude_scope: & crate :: item_scope:: ItemScope = & prelude_def_map. modules [ prelude_module. local_id ] . scope ;
54
+ let prelude_scope: & crate :: item_scope:: ItemScope =
55
+ & prelude_def_map. modules [ prelude_module. local_id ] . scope ;
46
56
if let Some ( ( name, vis) ) = prelude_scope. reverse_get ( item) {
47
57
if vis. is_visible_from ( db, from) {
48
58
return Some ( ModPath :: from_simple_segments ( PathKind :: Plain , vec ! [ name. clone( ) ] ) ) ;
@@ -68,7 +78,8 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
68
78
let mut candidate_paths = Vec :: new ( ) ;
69
79
for ( module_id, name) in importable_locations {
70
80
// TODO prevent infinite loops
71
- let mut path = match find_path ( db, ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id) ) , from) {
81
+ let mut path = match find_path ( db, ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id) ) , from)
82
+ {
72
83
None => continue ,
73
84
Some ( path) => path,
74
85
} ;
@@ -78,33 +89,58 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
78
89
candidate_paths. into_iter ( ) . min_by_key ( |path| path. segments . len ( ) )
79
90
}
80
91
81
- fn find_importable_locations ( db : & impl DefDatabase , item : ItemInNs , from : ModuleId ) -> Vec < ( ModuleId , Name ) > {
92
+ fn find_importable_locations (
93
+ db : & impl DefDatabase ,
94
+ item : ItemInNs ,
95
+ from : ModuleId ,
96
+ ) -> Vec < ( ModuleId , Name ) > {
82
97
let crate_graph = db. crate_graph ( ) ;
83
98
let mut result = Vec :: new ( ) ;
84
- for krate in Some ( from. krate ) . into_iter ( ) . chain ( crate_graph. dependencies ( from. krate ) . map ( |dep| dep. crate_id ) ) {
85
- let def_map = db. crate_def_map ( krate) ;
86
- for ( local_id, data) in def_map. modules . iter ( ) {
87
- if let Some ( ( name, vis) ) = data. scope . reverse_get ( item) {
88
- let is_private = if let crate :: visibility:: Visibility :: Module ( private_to) = vis {
89
- private_to. local_id == local_id
90
- } else { false } ;
91
- let is_original_def = if let Some ( module_def_id) = item. as_module_def_id ( ) {
92
- data. scope . declarations ( ) . any ( |it| it == module_def_id)
93
- } else { false } ;
94
- if is_private && !is_original_def {
95
- // Ignore private imports. these could be used if we are
96
- // in a submodule of this module, but that's usually not
97
- // what the user wants; and if this module can import
98
- // the item and we're a submodule of it, so can we.
99
- continue ;
100
- }
101
- if vis. is_visible_from ( db, from) {
102
- result. push ( ( ModuleId { krate, local_id } , name. clone ( ) ) ) ;
103
- }
99
+ for krate in Some ( from. krate )
100
+ . into_iter ( )
101
+ . chain ( crate_graph. dependencies ( from. krate ) . map ( |dep| dep. crate_id ) )
102
+ {
103
+ result. extend (
104
+ db. importable_locations_in_crate ( item, krate)
105
+ . iter ( )
106
+ . filter ( |( _, _, vis) | vis. is_visible_from ( db, from) )
107
+ . map ( |( m, n, _) | ( * m, n. clone ( ) ) ) ,
108
+ ) ;
109
+ }
110
+ result
111
+ }
112
+
113
+ pub ( crate ) fn importable_locations_in_crate_query (
114
+ db : & impl DefDatabase ,
115
+ item : ItemInNs ,
116
+ krate : CrateId ,
117
+ ) -> std:: sync:: Arc < [ ( ModuleId , Name , Visibility ) ] > {
118
+ let def_map = db. crate_def_map ( krate) ;
119
+ let mut result = Vec :: new ( ) ;
120
+ for ( local_id, data) in def_map. modules . iter ( ) {
121
+ if let Some ( ( name, vis) ) = data. scope . reverse_get ( item) {
122
+ let is_private = if let Visibility :: Module ( private_to) = vis {
123
+ private_to. local_id == local_id
124
+ } else {
125
+ false
126
+ } ;
127
+ let is_original_def = if let Some ( module_def_id) = item. as_module_def_id ( ) {
128
+ data. scope . declarations ( ) . any ( |it| it == module_def_id)
129
+ } else {
130
+ false
131
+ } ;
132
+ if is_private && !is_original_def {
133
+ // Ignore private imports. these could be used if we are
134
+ // in a submodule of this module, but that's usually not
135
+ // what the user wants; and if this module can import
136
+ // the item and we're a submodule of it, so can we.
137
+ // Also this keeps the cached data smaller.
138
+ continue ;
104
139
}
140
+ result. push ( ( ModuleId { krate, local_id } , name. clone ( ) , vis) ) ;
105
141
}
106
142
}
107
- result
143
+ result. into ( )
108
144
}
109
145
110
146
#[ cfg( test) ]
0 commit comments