11//! Look up accessible paths for items.
22use hir:: {
33 AsAssocItem , AssocItem , AssocItemContainer , Crate , ItemInNs , MacroDef , ModPath , Module ,
4- ModuleDef , Name , PathResolution , PrefixKind , ScopeDef , Semantics , Type ,
4+ ModuleDef , PathResolution , PrefixKind , ScopeDef , Semantics , Type ,
55} ;
66use itertools:: Itertools ;
77use rustc_hash:: FxHashSet ;
@@ -14,11 +14,16 @@ use crate::{
1414
1515use super :: item_name;
1616
17+ /// A candidate for import, derived during various IDE activities:
18+ /// * completion with imports on the fly proposals
19+ /// * completion edit resolve requests
20+ /// * assists
21+ /// * etc.
1722#[ derive( Debug ) ]
1823pub enum ImportCandidate {
19- // A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
24+ /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
2025 Path ( PathImportCandidate ) ,
21- /// A trait associated function (with no self parameter) or associated constant.
26+ /// A trait associated function (with no self parameter) or an associated constant.
2227 /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type
2328 /// and `name` is the `test_function`
2429 TraitAssocItem ( TraitImportCandidate ) ,
@@ -28,27 +33,40 @@ pub enum ImportCandidate {
2833 TraitMethod ( TraitImportCandidate ) ,
2934}
3035
36+ /// A trait import needed for a given associated item access.
37+ /// For `some::path::SomeStruct::ASSOC_`, contains the
38+ /// type of `some::path::SomeStruct` and `ASSOC_` as the item name.
3139#[ derive( Debug ) ]
3240pub struct TraitImportCandidate {
41+ /// A type of the item that has the associated item accessed at.
3342 pub receiver_ty : Type ,
34- pub name : NameToImport ,
43+ /// The associated item name that the trait to import should contain.
44+ pub assoc_item_name : NameToImport ,
3545}
3646
47+ /// Path import for a given name, qualified or not.
3748#[ derive( Debug ) ]
3849pub struct PathImportCandidate {
39- pub qualifier : Qualifier ,
50+ /// Optional qualifier before name.
51+ pub qualifier : Option < FirstSegmentUnresolved > ,
52+ /// The name the item (struct, trait, enum, etc.) should have.
4053 pub name : NameToImport ,
4154}
4255
56+ /// A qualifier that has a first segment and it's unresolved.
4357#[ derive( Debug ) ]
44- pub enum Qualifier {
45- Absent ,
46- FirstSegmentUnresolved ( ast :: NameRef , ModPath ) ,
58+ pub struct FirstSegmentUnresolved {
59+ fist_segment : ast :: NameRef ,
60+ full_qualifier : ModPath ,
4761}
4862
63+ /// A name that will be used during item lookups.
4964#[ derive( Debug ) ]
5065pub enum NameToImport {
66+ /// Requires items with names that exactly match the given string, case-sensitive.
5167 Exact ( String ) ,
68+ /// Requires items with names that case-insensitively contain all letters from the string,
69+ /// in the same order, but not necessary adjacent.
5270 Fuzzy ( String ) ,
5371}
5472
@@ -61,6 +79,7 @@ impl NameToImport {
6179 }
6280}
6381
82+ /// A struct to find imports in the project, given a certain name (or its part) and the context.
6483#[ derive( Debug ) ]
6584pub struct ImportAssets {
6685 import_candidate : ImportCandidate ,
@@ -119,19 +138,30 @@ impl ImportAssets {
119138 Some ( Self {
120139 import_candidate : ImportCandidate :: TraitMethod ( TraitImportCandidate {
121140 receiver_ty,
122- name : NameToImport :: Fuzzy ( fuzzy_method_name) ,
141+ assoc_item_name : NameToImport :: Fuzzy ( fuzzy_method_name) ,
123142 } ) ,
124143 module_with_candidate : module_with_method_call,
125144 candidate_node,
126145 } )
127146 }
128147}
129148
149+ /// An import (not necessary the only one) that corresponds a certain given [`PathImportCandidate`].
150+ /// (the structure is not entirely correct, since there can be situations requiring two imports, see FIXME below for the details)
130151#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
131152pub struct LocatedImport {
153+ /// The path to use in the `use` statement for a given candidate to be imported.
132154 pub import_path : ModPath ,
155+ /// An item that will be imported with the import path given.
133156 pub item_to_import : ItemInNs ,
157+ /// The path import candidate, resolved.
158+ ///
159+ /// Not necessary matches the import:
160+ /// For any associated constant from the trait, we try to access as `some::path::SomeStruct::ASSOC_`
161+ /// the original item is the associated constant, but the import has to be a trait that
162+ /// defines this constant.
134163 pub original_item : ItemInNs ,
164+ /// A path of the original item.
135165 pub original_path : Option < ModPath > ,
136166}
137167
@@ -144,15 +174,6 @@ impl LocatedImport {
144174 ) -> Self {
145175 Self { import_path, item_to_import, original_item, original_path }
146176 }
147-
148- pub fn original_item_name ( & self , db : & RootDatabase ) -> Option < Name > {
149- match self . original_item {
150- ItemInNs :: Types ( module_def_id) | ItemInNs :: Values ( module_def_id) => {
151- ModuleDef :: from ( module_def_id) . name ( db)
152- }
153- ItemInNs :: Macros ( macro_def_id) => MacroDef :: from ( macro_def_id) . name ( db) ,
154- }
155- }
156177}
157178
158179impl ImportAssets {
@@ -229,7 +250,7 @@ impl ImportAssets {
229250 match & self . import_candidate {
230251 ImportCandidate :: Path ( candidate) => & candidate. name ,
231252 ImportCandidate :: TraitAssocItem ( candidate)
232- | ImportCandidate :: TraitMethod ( candidate) => & candidate. name ,
253+ | ImportCandidate :: TraitMethod ( candidate) => & candidate. assoc_item_name ,
233254 }
234255 }
235256
@@ -279,17 +300,18 @@ fn path_applicable_imports(
279300 let _p = profile:: span ( "import_assets::path_applicable_imports" ) ;
280301
281302 let ( unresolved_first_segment, unresolved_qualifier) = match & path_candidate. qualifier {
282- Qualifier :: Absent => {
303+ None => {
283304 return items_with_candidate_name
284305 . into_iter ( )
285306 . filter_map ( |item| {
286307 Some ( LocatedImport :: new ( mod_path ( item) ?, item, item, mod_path ( item) ) )
287308 } )
288309 . collect ( ) ;
289310 }
290- Qualifier :: FirstSegmentUnresolved ( first_segment, qualifier) => {
291- ( first_segment. to_string ( ) , qualifier. to_string ( ) )
292- }
311+ Some ( first_segment_unresolved) => (
312+ first_segment_unresolved. fist_segment . to_string ( ) ,
313+ first_segment_unresolved. full_qualifier . to_string ( ) ,
314+ ) ,
293315 } ;
294316
295317 items_with_candidate_name
@@ -516,7 +538,7 @@ impl ImportCandidate {
516538 Some ( _) => None ,
517539 None => Some ( Self :: TraitMethod ( TraitImportCandidate {
518540 receiver_ty : sema. type_of_expr ( & method_call. receiver ( ) ?) ?,
519- name : NameToImport :: Exact ( method_call. name_ref ( ) ?. to_string ( ) ) ,
541+ assoc_item_name : NameToImport :: Exact ( method_call. name_ref ( ) ?. to_string ( ) ) ,
520542 } ) ) ,
521543 }
522544 }
@@ -559,10 +581,10 @@ fn path_import_candidate(
559581 qualifier_start. syntax ( ) . ancestors ( ) . find_map ( ast:: Path :: cast) ?;
560582 if sema. resolve_path ( & qualifier_start_path) . is_none ( ) {
561583 ImportCandidate :: Path ( PathImportCandidate {
562- qualifier : Qualifier :: FirstSegmentUnresolved (
563- qualifier_start,
564- ModPath :: from_src_unhygienic ( qualifier) ?,
565- ) ,
584+ qualifier : Some ( FirstSegmentUnresolved {
585+ fist_segment : qualifier_start,
586+ full_qualifier : ModPath :: from_src_unhygienic ( qualifier) ?,
587+ } ) ,
566588 name,
567589 } )
568590 } else {
@@ -572,12 +594,12 @@ fn path_import_candidate(
572594 Some ( PathResolution :: Def ( ModuleDef :: Adt ( assoc_item_path) ) ) => {
573595 ImportCandidate :: TraitAssocItem ( TraitImportCandidate {
574596 receiver_ty : assoc_item_path. ty ( sema. db ) ,
575- name,
597+ assoc_item_name : name,
576598 } )
577599 }
578600 Some ( _) => return None ,
579601 } ,
580- None => ImportCandidate :: Path ( PathImportCandidate { qualifier : Qualifier :: Absent , name } ) ,
602+ None => ImportCandidate :: Path ( PathImportCandidate { qualifier : None , name } ) ,
581603 } )
582604}
583605
0 commit comments