@@ -8,22 +8,12 @@ use crate::{
8
8
} ;
9
9
use hir_expand:: name:: Name ;
10
10
11
- // TODO handle prelude
12
- // TODO handle enum variants
13
11
// TODO don't import from super imports? or at least deprioritize
14
12
// TODO use super?
15
13
// TODO use shortest path
16
14
// TODO performance / memoize
17
15
18
16
pub fn find_path ( db : & impl DefDatabase , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
19
- // 1. Find all locations that the item could be imported from (i.e. that are visible)
20
- // - this needs to consider other crates, for reexports from transitive dependencies
21
- // - filter by visibility
22
- // 2. For each of these, go up the module tree until we find an
23
- // item/module/crate that is already in scope (including because it is in
24
- // the prelude, and including aliases!)
25
- // 3. Then select the one that gives the shortest path
26
-
27
17
// Base cases:
28
18
29
19
// - if the item is already in scope, return the name under which it is
@@ -46,10 +36,28 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
46
36
}
47
37
48
38
// - if the item is in the prelude, return the name from there
49
- // TODO check prelude
39
+ if let Some ( prelude_module) = def_map. prelude {
40
+ let prelude_def_map = db. crate_def_map ( prelude_module. krate ) ;
41
+ let prelude_scope: & crate :: item_scope:: ItemScope = & prelude_def_map. modules [ prelude_module. local_id ] . scope ;
42
+ if let Some ( ( name, vis) ) = prelude_scope. reverse_get ( item) {
43
+ if vis. is_visible_from ( db, from) {
44
+ return Some ( ModPath :: from_simple_segments ( PathKind :: Plain , vec ! [ name. clone( ) ] ) ) ;
45
+ }
46
+ }
47
+ }
50
48
51
49
// Recursive case:
52
50
// - if the item is an enum variant, refer to it via the enum
51
+ if let Some ( ModuleDefId :: EnumVariantId ( variant) ) = item. as_module_def_id ( ) {
52
+ if let Some ( mut path) = find_path ( db, ItemInNs :: Types ( variant. parent . into ( ) ) , from) {
53
+ let data = db. enum_data ( variant. parent ) ;
54
+ path. segments . push ( data. variants [ variant. local_id ] . name . clone ( ) ) ;
55
+ return Some ( path) ;
56
+ }
57
+ // If this doesn't work, it seems we have no way of referring to the
58
+ // enum; that's very weird, but there might still be a reexport of the
59
+ // variant somewhere
60
+ }
53
61
54
62
// - otherwise, look for modules containing (reexporting) it and import it from one of those
55
63
let importable_locations = find_importable_locations ( db, item, from) ;
@@ -131,6 +139,16 @@ mod tests {
131
139
check_found_path ( code, "S" ) ;
132
140
}
133
141
142
+ #[ test]
143
+ fn enum_variant ( ) {
144
+ let code = r#"
145
+ //- /main.rs
146
+ enum E { A }
147
+ <|>
148
+ "# ;
149
+ check_found_path ( code, "E::A" ) ;
150
+ }
151
+
134
152
#[ test]
135
153
fn sub_module ( ) {
136
154
let code = r#"
@@ -215,6 +233,19 @@ mod tests {
215
233
check_found_path ( code, "bar::U" ) ;
216
234
}
217
235
236
+ #[ test]
237
+ fn different_crate_reexport ( ) {
238
+ let code = r#"
239
+ //- /main.rs crate:main deps:std
240
+ <|>
241
+ //- /std.rs crate:std deps:core
242
+ pub use core::S;
243
+ //- /core.rs crate:core
244
+ pub struct S;
245
+ "# ;
246
+ check_found_path ( code, "std::S" ) ;
247
+ }
248
+
218
249
#[ test]
219
250
fn prelude ( ) {
220
251
let code = r#"
@@ -227,4 +258,21 @@ mod tests {
227
258
"# ;
228
259
check_found_path ( code, "S" ) ;
229
260
}
261
+
262
+ #[ test]
263
+ fn enum_variant_from_prelude ( ) {
264
+ let code = r#"
265
+ //- /main.rs crate:main deps:std
266
+ <|>
267
+ //- /std.rs crate:std
268
+ pub mod prelude {
269
+ pub enum Option<T> { Some(T), None }
270
+ pub use Option::*;
271
+ }
272
+ #[prelude_import]
273
+ pub use prelude::*;
274
+ "# ;
275
+ check_found_path ( code, "None" ) ;
276
+ check_found_path ( code, "Some" ) ;
277
+ }
230
278
}
0 commit comments