11//! See [`import_on_the_fly`].
22use hir:: { ItemInNs , ModuleDef } ;
33use ide_db:: imports:: {
4- import_assets:: { ImportAssets , ImportCandidate , LocatedImport } ,
4+ import_assets:: { ImportAssets , LocatedImport } ,
55 insert_use:: ImportScope ,
66} ;
77use itertools:: Itertools ;
8- use syntax:: { AstNode , SyntaxNode , T } ;
8+ use syntax:: { ast , AstNode , SyntaxNode , T } ;
99
1010use crate :: {
1111 context:: {
12- CompletionContext , NameRefContext , NameRefKind , PathCompletionCtx , PathKind ,
13- PatternContext , TypeLocation ,
12+ CompletionContext , DotAccess , PathCompletionCtx , PathKind , PatternContext , Qualified ,
13+ TypeLocation ,
1414 } ,
1515 render:: { render_resolution_with_import, RenderContext } ,
1616} ;
@@ -108,45 +108,108 @@ use super::Completions;
108108// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
109109// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
110110// capability enabled.
111- pub ( crate ) fn import_on_the_fly ( acc : & mut Completions , ctx : & CompletionContext ) -> Option < ( ) > {
111+ pub ( crate ) fn import_on_the_fly_path (
112+ acc : & mut Completions ,
113+ ctx : & CompletionContext ,
114+ path_ctx : & PathCompletionCtx ,
115+ ) -> Option < ( ) > {
112116 if !ctx. config . enable_imports_on_the_fly {
113117 return None ;
114118 }
115- let path_kind = match ctx . nameref_ctx ( ) {
116- Some ( NameRefContext {
119+ let ( kind , qualified ) = match path_ctx {
120+ PathCompletionCtx {
117121 kind :
118- Some ( NameRefKind :: Path ( PathCompletionCtx {
119- kind :
120- kind @ ( PathKind :: Expr { .. }
121- | PathKind :: Type { .. }
122- | PathKind :: Attr { .. }
123- | PathKind :: Derive { .. }
124- | PathKind :: Pat ) ,
125- ..
126- } ) ) ,
122+ kind @ ( PathKind :: Expr { .. }
123+ | PathKind :: Type { .. }
124+ | PathKind :: Attr { .. }
125+ | PathKind :: Derive { .. }
126+ | PathKind :: Pat ) ,
127+ qualified,
127128 ..
128- } ) => Some ( kind) ,
129- Some ( NameRefContext { kind : Some ( NameRefKind :: DotAccess ( _) ) , .. } ) => None ,
130- None if matches ! ( ctx. pattern_ctx, Some ( PatternContext { record_pat: None , .. } ) ) => {
131- Some ( & PathKind :: Pat )
132- }
129+ } => ( Some ( kind) , qualified) ,
133130 _ => return None ,
134131 } ;
132+ let potential_import_name = import_name ( ctx) ;
133+ let qualifier = match qualified {
134+ Qualified :: With { path, .. } => Some ( path. clone ( ) ) ,
135+ _ => None ,
136+ } ;
137+ let import_assets = import_assets_for_path ( ctx, & potential_import_name, qualifier. clone ( ) ) ?;
135138
136- let potential_import_name = {
137- let token_kind = ctx. token . kind ( ) ;
138- if matches ! ( token_kind, T ![ . ] | T ![ :: ] ) {
139- String :: new ( )
140- } else {
141- ctx. token . to_string ( )
142- }
139+ import_on_the_fly (
140+ acc,
141+ ctx,
142+ kind,
143+ import_assets,
144+ qualifier. map ( |it| it. syntax ( ) . clone ( ) ) . or_else ( || ctx. original_token . parent ( ) ) ?,
145+ potential_import_name,
146+ )
147+ }
148+
149+ pub ( crate ) fn import_on_the_fly_dot (
150+ acc : & mut Completions ,
151+ ctx : & CompletionContext ,
152+ dot_access : & DotAccess ,
153+ ) -> Option < ( ) > {
154+ if !ctx. config . enable_imports_on_the_fly {
155+ return None ;
156+ }
157+ let receiver = dot_access. receiver . as_ref ( ) ?;
158+ let ty = dot_access. receiver_ty . as_ref ( ) ?;
159+ let potential_import_name = import_name ( ctx) ;
160+ let import_assets = ImportAssets :: for_fuzzy_method_call (
161+ ctx. module ,
162+ ty. original . clone ( ) ,
163+ potential_import_name. clone ( ) ,
164+ receiver. syntax ( ) . clone ( ) ,
165+ ) ?;
166+
167+ import_on_the_fly (
168+ acc,
169+ ctx,
170+ None ,
171+ import_assets,
172+ receiver. syntax ( ) . clone ( ) ,
173+ potential_import_name,
174+ )
175+ }
176+
177+ pub ( crate ) fn import_on_the_fly_pat (
178+ acc : & mut Completions ,
179+ ctx : & CompletionContext ,
180+ pat_ctx : & PatternContext ,
181+ ) -> Option < ( ) > {
182+ if !ctx. config . enable_imports_on_the_fly {
183+ return None ;
184+ }
185+ let kind = match pat_ctx {
186+ PatternContext { record_pat : None , .. } => PathKind :: Pat ,
187+ _ => return None ,
143188 } ;
144189
190+ let potential_import_name = import_name ( ctx) ;
191+ let import_assets = import_assets_for_path ( ctx, & potential_import_name, None ) ?;
192+
193+ import_on_the_fly (
194+ acc,
195+ ctx,
196+ Some ( & kind) ,
197+ import_assets,
198+ ctx. original_token . parent ( ) ?,
199+ potential_import_name,
200+ )
201+ }
202+
203+ fn import_on_the_fly (
204+ acc : & mut Completions ,
205+ ctx : & CompletionContext ,
206+ path_kind : Option < & PathKind > ,
207+ import_assets : ImportAssets ,
208+ position : SyntaxNode ,
209+ potential_import_name : String ,
210+ ) -> Option < ( ) > {
145211 let _p = profile:: span ( "import_on_the_fly" ) . detail ( || potential_import_name. clone ( ) ) ;
146212
147- let user_input_lowercased = potential_import_name. to_lowercase ( ) ;
148- let import_assets = import_assets ( ctx, potential_import_name) ?;
149- let position = position_for_import ( ctx, Some ( import_assets. import_candidate ( ) ) ) ?;
150213 if ImportScope :: find_insert_use_container ( & position, & ctx. sema ) . is_none ( ) {
151214 return None ;
152215 }
@@ -194,6 +257,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
194257 ( PathKind :: Derive { .. } , _) => false ,
195258 }
196259 } ;
260+ let user_input_lowercased = potential_import_name. to_lowercase ( ) ;
197261
198262 acc. add_all (
199263 import_assets
@@ -216,47 +280,36 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
216280 Some ( ( ) )
217281}
218282
219- pub ( crate ) fn position_for_import (
220- ctx : & CompletionContext ,
221- import_candidate : Option < & ImportCandidate > ,
222- ) -> Option < SyntaxNode > {
223- Some (
224- match import_candidate {
225- Some ( ImportCandidate :: TraitAssocItem ( _) ) => ctx. path_qual ( ) ?. syntax ( ) ,
226- Some ( ImportCandidate :: TraitMethod ( _) ) => ctx. dot_receiver ( ) ?. syntax ( ) ,
227- Some ( ImportCandidate :: Path ( _) ) | None => return ctx. original_token . parent ( ) ,
228- }
229- . clone ( ) ,
230- )
283+ fn import_name ( ctx : & CompletionContext ) -> String {
284+ let token_kind = ctx. token . kind ( ) ;
285+ if matches ! ( token_kind, T ![ . ] | T ![ :: ] ) {
286+ String :: new ( )
287+ } else {
288+ ctx. token . to_string ( )
289+ }
231290}
232291
233- fn import_assets ( ctx : & CompletionContext , fuzzy_name : String ) -> Option < ImportAssets > {
234- let current_module = ctx. module ;
235- if let Some ( dot_receiver) = ctx. dot_receiver ( ) {
236- ImportAssets :: for_fuzzy_method_call (
237- current_module,
238- ctx. sema . type_of_expr ( dot_receiver) ?. original ,
239- fuzzy_name,
240- dot_receiver. syntax ( ) . clone ( ) ,
241- )
242- } else {
243- let fuzzy_name_length = fuzzy_name. len ( ) ;
244- let mut assets_for_path = ImportAssets :: for_fuzzy_path (
245- current_module,
246- ctx. path_qual ( ) . cloned ( ) ,
247- fuzzy_name,
248- & ctx. sema ,
249- ctx. token . parent ( ) ?,
250- ) ?;
251- if fuzzy_name_length < 3 {
252- cov_mark:: hit!( flyimport_exact_on_short_path) ;
253- assets_for_path. path_fuzzy_name_to_exact ( false ) ;
254- }
255- Some ( assets_for_path)
292+ fn import_assets_for_path (
293+ ctx : & CompletionContext ,
294+ potential_import_name : & str ,
295+ qualifier : Option < ast:: Path > ,
296+ ) -> Option < ImportAssets > {
297+ let fuzzy_name_length = potential_import_name. len ( ) ;
298+ let mut assets_for_path = ImportAssets :: for_fuzzy_path (
299+ ctx. module ,
300+ qualifier,
301+ potential_import_name. to_owned ( ) ,
302+ & ctx. sema ,
303+ ctx. token . parent ( ) ?,
304+ ) ?;
305+ if fuzzy_name_length < 3 {
306+ cov_mark:: hit!( flyimport_exact_on_short_path) ;
307+ assets_for_path. path_fuzzy_name_to_exact ( false ) ;
256308 }
309+ Some ( assets_for_path)
257310}
258311
259- pub ( crate ) fn compute_fuzzy_completion_order_key (
312+ fn compute_fuzzy_completion_order_key (
260313 proposed_mod_path : & hir:: ModPath ,
261314 user_input_lowercased : & str ,
262315) -> usize {
0 commit comments