1
1
//! See [`import_on_the_fly`].
2
2
use hir:: { ItemInNs , ModuleDef } ;
3
3
use ide_db:: imports:: {
4
- import_assets:: { ImportAssets , ImportCandidate , LocatedImport } ,
4
+ import_assets:: { ImportAssets , LocatedImport } ,
5
5
insert_use:: ImportScope ,
6
6
} ;
7
7
use itertools:: Itertools ;
8
- use syntax:: { AstNode , SyntaxNode , T } ;
8
+ use syntax:: { ast , AstNode , SyntaxNode , T } ;
9
9
10
10
use crate :: {
11
11
context:: {
12
- CompletionContext , NameRefContext , NameRefKind , PathCompletionCtx , PathKind ,
13
- PatternContext , TypeLocation ,
12
+ CompletionContext , DotAccess , PathCompletionCtx , PathKind , PatternContext , Qualified ,
13
+ TypeLocation ,
14
14
} ,
15
15
render:: { render_resolution_with_import, RenderContext } ,
16
16
} ;
@@ -108,45 +108,108 @@ use super::Completions;
108
108
// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
109
109
// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
110
110
// 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 < ( ) > {
112
116
if !ctx. config . enable_imports_on_the_fly {
113
117
return None ;
114
118
}
115
- let path_kind = match ctx . nameref_ctx ( ) {
116
- Some ( NameRefContext {
119
+ let ( kind , qualified ) = match path_ctx {
120
+ PathCompletionCtx {
117
121
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,
127
128
..
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) ,
133
130
_ => return None ,
134
131
} ;
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 ( ) ) ?;
135
138
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 ,
143
188
} ;
144
189
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 < ( ) > {
145
211
let _p = profile:: span ( "import_on_the_fly" ) . detail ( || potential_import_name. clone ( ) ) ;
146
212
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 ( ) ) ) ?;
150
213
if ImportScope :: find_insert_use_container ( & position, & ctx. sema ) . is_none ( ) {
151
214
return None ;
152
215
}
@@ -194,6 +257,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
194
257
( PathKind :: Derive { .. } , _) => false ,
195
258
}
196
259
} ;
260
+ let user_input_lowercased = potential_import_name. to_lowercase ( ) ;
197
261
198
262
acc. add_all (
199
263
import_assets
@@ -216,47 +280,36 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
216
280
Some ( ( ) )
217
281
}
218
282
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
+ }
231
290
}
232
291
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 ) ;
256
308
}
309
+ Some ( assets_for_path)
257
310
}
258
311
259
- pub ( crate ) fn compute_fuzzy_completion_order_key (
312
+ fn compute_fuzzy_completion_order_key (
260
313
proposed_mod_path : & hir:: ModPath ,
261
314
user_input_lowercased : & str ,
262
315
) -> usize {
0 commit comments