@@ -8,8 +8,10 @@ use hir::{
88 SemanticsScope , Trait , Type ,
99} ;
1010use itertools:: Itertools ;
11+ use parser:: SyntaxKind ;
1112use rustc_hash:: { FxHashMap , FxHashSet } ;
1213use smallvec:: { SmallVec , smallvec} ;
14+ use stdx:: never;
1315use syntax:: {
1416 AstNode , SyntaxNode ,
1517 ast:: { self , HasName , make} ,
@@ -61,6 +63,103 @@ pub struct TraitImportCandidate<'db> {
6163 pub assoc_item_name : NameToImport ,
6264}
6365
66+ #[ derive( Debug ) ]
67+ struct PathDefinitionKinds {
68+ modules : bool ,
69+ bang_macros : bool ,
70+ // FIXME: Distinguish between attr and derive macros.
71+ attr_macros : bool ,
72+ value_namespace : bool ,
73+ type_namespace : bool ,
74+ /// Unions, record structs and record enum variants. Note that unions and structs
75+ /// can also be enabled by `type_namespace` (either works).
76+ records : bool ,
77+ /// Tuple structs and tuple enum variants. Both are also controlled by `value_namespace`
78+ /// (either works). Structs are also covered by `type_namespace`.
79+ tuple_structs : bool ,
80+ /// Structs, enum variants and consts.
81+ structs_and_consts : bool ,
82+ }
83+
84+ impl PathDefinitionKinds {
85+ const ALL_DISABLED : Self = Self {
86+ modules : false ,
87+ bang_macros : false ,
88+ attr_macros : false ,
89+ value_namespace : false ,
90+ type_namespace : false ,
91+ records : false ,
92+ tuple_structs : false ,
93+ structs_and_consts : false ,
94+ } ;
95+ const ALL_ENABLED : Self = Self {
96+ modules : true ,
97+ bang_macros : true ,
98+ attr_macros : true ,
99+ value_namespace : true ,
100+ type_namespace : true ,
101+ records : true ,
102+ tuple_structs : true ,
103+ structs_and_consts : true ,
104+ } ;
105+ // While a path pattern only allows unit structs/enum variants, parentheses/braces may be written later.
106+ const PATH_PAT_KINDS : PathDefinitionKinds =
107+ Self { structs_and_consts : true , bang_macros : true , ..Self :: ALL_DISABLED } ;
108+
109+ fn deduce_from_path ( path : & ast:: Path , exact : bool ) -> Self {
110+ let Some ( parent) = path. syntax ( ) . parent ( ) else {
111+ return Self :: ALL_ENABLED ;
112+ } ;
113+ let mut result = match parent. kind ( ) {
114+ // When there are following segments, it can be a type (with a method) or a module.
115+ // Technically, a type can only have up to 2 segments following (an associated type
116+ // then a method), but most paths are shorter than 3 segments anyway, and we'll also
117+ // validate that the following segment resolve.
118+ SyntaxKind :: PATH => Self { modules : true , type_namespace : true , ..Self :: ALL_DISABLED } ,
119+ SyntaxKind :: MACRO_CALL => Self { bang_macros : true , ..Self :: ALL_DISABLED } ,
120+ SyntaxKind :: META => Self { attr_macros : true , ..Self :: ALL_DISABLED } ,
121+ SyntaxKind :: USE_TREE => {
122+ if ast:: UseTree :: cast ( parent) . unwrap ( ) . use_tree_list ( ) . is_some ( ) {
123+ Self { modules : true , ..Self :: ALL_DISABLED }
124+ } else {
125+ Self :: ALL_ENABLED
126+ }
127+ }
128+ SyntaxKind :: VISIBILITY => Self { modules : true , ..Self :: ALL_DISABLED } ,
129+ SyntaxKind :: ASM_SYM => Self { value_namespace : true , ..Self :: ALL_DISABLED } ,
130+ // `bang_macros = true` because you can still type the `!`.
131+ // `type_namespace = true` because you can type `::method()`.
132+ SyntaxKind :: PATH_EXPR => Self {
133+ value_namespace : true ,
134+ bang_macros : true ,
135+ type_namespace : true ,
136+ ..Self :: ALL_DISABLED
137+ } ,
138+ SyntaxKind :: PATH_PAT => Self :: PATH_PAT_KINDS ,
139+ SyntaxKind :: TUPLE_STRUCT_PAT => {
140+ Self { tuple_structs : true , bang_macros : true , ..Self :: ALL_DISABLED }
141+ }
142+ SyntaxKind :: RECORD_EXPR | SyntaxKind :: RECORD_PAT => {
143+ Self { records : true , bang_macros : true , ..Self :: ALL_DISABLED }
144+ }
145+ SyntaxKind :: PATH_TYPE => {
146+ Self { type_namespace : true , bang_macros : true , ..Self :: ALL_DISABLED }
147+ }
148+ SyntaxKind :: ERROR => Self :: ALL_ENABLED ,
149+ _ => {
150+ never ! ( "this match should cover all possible parents of paths\n parent={parent:#?}" ) ;
151+ Self :: ALL_ENABLED
152+ }
153+ } ;
154+ if !exact {
155+ // When the path is not required to be exact, there could be additional segments to be filled.
156+ result. modules = true ;
157+ result. type_namespace = true ;
158+ }
159+ result
160+ }
161+ }
162+
64163/// Path import for a given name, qualified or not.
65164#[ derive( Debug ) ]
66165pub struct PathImportCandidate {
@@ -70,6 +169,8 @@ pub struct PathImportCandidate {
70169 pub name : NameToImport ,
71170 /// Potentially more segments that should resolve in the candidate.
72171 pub after : Vec < Name > ,
172+ /// The kind of definitions that we can include.
173+ definition_kinds : PathDefinitionKinds ,
73174}
74175
75176/// A name that will be used during item lookups.
@@ -168,13 +269,14 @@ impl<'db> ImportAssets<'db> {
168269
169270 pub fn for_fuzzy_path (
170271 module_with_candidate : Module ,
272+ path : Option < & ast:: Path > ,
171273 qualifier : Option < ast:: Path > ,
172274 fuzzy_name : String ,
173275 sema : & Semantics < ' db , RootDatabase > ,
174276 candidate_node : SyntaxNode ,
175277 ) -> Option < Self > {
176278 Some ( Self {
177- import_candidate : ImportCandidate :: for_fuzzy_path ( qualifier, fuzzy_name, sema) ?,
279+ import_candidate : ImportCandidate :: for_fuzzy_path ( path , qualifier, fuzzy_name, sema) ?,
178280 module_with_candidate,
179281 candidate_node,
180282 } )
@@ -394,6 +496,9 @@ fn path_applicable_imports(
394496 // see also an ignored test under FIXME comment in the qualify_path.rs module
395497 AssocSearchMode :: Exclude ,
396498 )
499+ . filter ( |( item, _) | {
500+ filter_by_definition_kind ( db, * item, & path_candidate. definition_kinds )
501+ } )
397502 . filter_map ( |( item, do_not_complete) | {
398503 if !scope_filter ( item) {
399504 return None ;
@@ -442,6 +547,46 @@ fn path_applicable_imports(
442547 result
443548}
444549
550+ fn filter_by_definition_kind (
551+ db : & RootDatabase ,
552+ item : ItemInNs ,
553+ allowed : & PathDefinitionKinds ,
554+ ) -> bool {
555+ let item = item. into_module_def ( ) ;
556+ let struct_per_kind = |struct_kind| {
557+ allowed. structs_and_consts
558+ || match struct_kind {
559+ hir:: StructKind :: Record => allowed. records ,
560+ hir:: StructKind :: Tuple => allowed. value_namespace || allowed. tuple_structs ,
561+ hir:: StructKind :: Unit => allowed. value_namespace ,
562+ }
563+ } ;
564+ match item {
565+ ModuleDef :: Module ( _) => allowed. modules ,
566+ ModuleDef :: Function ( _) => allowed. value_namespace ,
567+ ModuleDef :: Adt ( hir:: Adt :: Struct ( item) ) => {
568+ allowed. type_namespace || struct_per_kind ( item. kind ( db) )
569+ }
570+ ModuleDef :: Adt ( hir:: Adt :: Enum ( _) ) => allowed. type_namespace ,
571+ ModuleDef :: Adt ( hir:: Adt :: Union ( _) ) => {
572+ allowed. type_namespace || allowed. records || allowed. structs_and_consts
573+ }
574+ ModuleDef :: EnumVariant ( item) => struct_per_kind ( item. kind ( db) ) ,
575+ ModuleDef :: Const ( _) => allowed. value_namespace || allowed. structs_and_consts ,
576+ ModuleDef :: Static ( _) => allowed. value_namespace ,
577+ ModuleDef :: Trait ( _) => allowed. type_namespace ,
578+ ModuleDef :: TypeAlias ( _) => allowed. type_namespace ,
579+ ModuleDef :: BuiltinType ( _) => allowed. type_namespace ,
580+ ModuleDef :: Macro ( item) => {
581+ if item. is_fn_like ( db) {
582+ allowed. bang_macros
583+ } else {
584+ allowed. attr_macros
585+ }
586+ }
587+ }
588+ }
589+
445590fn filter_candidates_by_after_path (
446591 db : & RootDatabase ,
447592 scope : & SemanticsScope < ' _ > ,
@@ -835,6 +980,7 @@ impl<'db> ImportCandidate<'db> {
835980 . collect :: < Option < _ > > ( ) ?;
836981 path_import_candidate (
837982 sema,
983+ Some ( path) ,
838984 path. qualifier ( ) ,
839985 NameToImport :: exact_case_sensitive ( path. segment ( ) ?. name_ref ( ) ?. to_string ( ) ) ,
840986 after,
@@ -853,25 +999,31 @@ impl<'db> ImportCandidate<'db> {
853999 qualifier : vec ! [ ] ,
8541000 name : NameToImport :: exact_case_sensitive ( name. to_string ( ) ) ,
8551001 after : vec ! [ ] ,
1002+ definition_kinds : PathDefinitionKinds :: PATH_PAT_KINDS ,
8561003 } ) )
8571004 }
8581005
8591006 fn for_fuzzy_path (
1007+ path : Option < & ast:: Path > ,
8601008 qualifier : Option < ast:: Path > ,
8611009 fuzzy_name : String ,
8621010 sema : & Semantics < ' db , RootDatabase > ,
8631011 ) -> Option < Self > {
8641012 // Assume a fuzzy match does not want the segments after. Because... I guess why not?
865- path_import_candidate ( sema, qualifier, NameToImport :: fuzzy ( fuzzy_name) , Vec :: new ( ) )
1013+ path_import_candidate ( sema, path , qualifier, NameToImport :: fuzzy ( fuzzy_name) , Vec :: new ( ) )
8661014 }
8671015}
8681016
8691017fn path_import_candidate < ' db > (
8701018 sema : & Semantics < ' db , RootDatabase > ,
1019+ path : Option < & ast:: Path > ,
8711020 qualifier : Option < ast:: Path > ,
8721021 name : NameToImport ,
8731022 after : Vec < Name > ,
8741023) -> Option < ImportCandidate < ' db > > {
1024+ let definition_kinds = path. map_or ( PathDefinitionKinds :: ALL_ENABLED , |path| {
1025+ PathDefinitionKinds :: deduce_from_path ( path, matches ! ( name, NameToImport :: Exact ( ..) ) )
1026+ } ) ;
8751027 Some ( match qualifier {
8761028 Some ( qualifier) => match sema. resolve_path ( & qualifier) {
8771029 Some ( PathResolution :: Def ( ModuleDef :: BuiltinType ( _) ) ) | None => {
@@ -880,7 +1032,12 @@ fn path_import_candidate<'db>(
8801032 . segments ( )
8811033 . map ( |seg| seg. name_ref ( ) . map ( |name| Name :: new_root ( & name. text ( ) ) ) )
8821034 . collect :: < Option < Vec < _ > > > ( ) ?;
883- ImportCandidate :: Path ( PathImportCandidate { qualifier, name, after } )
1035+ ImportCandidate :: Path ( PathImportCandidate {
1036+ qualifier,
1037+ name,
1038+ after,
1039+ definition_kinds,
1040+ } )
8841041 } else {
8851042 return None ;
8861043 }
@@ -904,7 +1061,12 @@ fn path_import_candidate<'db>(
9041061 }
9051062 Some ( _) => return None ,
9061063 } ,
907- None => ImportCandidate :: Path ( PathImportCandidate { qualifier : vec ! [ ] , name, after } ) ,
1064+ None => ImportCandidate :: Path ( PathImportCandidate {
1065+ qualifier : vec ! [ ] ,
1066+ name,
1067+ after,
1068+ definition_kinds,
1069+ } ) ,
9081070 } )
9091071}
9101072
0 commit comments