Skip to content

Commit 69f3096

Browse files
committed
Auto merge of rust-lang#12573 - Veykril:completion, r=Veykril
internal: Split flyimport into its 3 applicable contexts
2 parents 09ac44c + 173bb10 commit 69f3096

File tree

6 files changed

+169
-130
lines changed

6 files changed

+169
-130
lines changed

crates/ide-completion/src/completions/flyimport.rs

Lines changed: 120 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
//! See [`import_on_the_fly`].
22
use hir::{ItemInNs, ModuleDef};
33
use ide_db::imports::{
4-
import_assets::{ImportAssets, ImportCandidate, LocatedImport},
4+
import_assets::{ImportAssets, LocatedImport},
55
insert_use::ImportScope,
66
};
77
use itertools::Itertools;
8-
use syntax::{AstNode, SyntaxNode, T};
8+
use syntax::{ast, AstNode, SyntaxNode, T};
99

1010
use 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 {

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ pub(crate) struct CompletionContext<'a> {
328328
// FIXME: This shouldn't exist
329329
pub(super) previous_token: Option<SyntaxToken>,
330330

331+
// We might wanna split these out of CompletionContext
331332
pub(super) ident_ctx: IdentContext,
332-
333333
pub(super) pattern_ctx: Option<PatternContext>,
334334
pub(super) qualifier_ctx: QualifierCtx,
335335

@@ -362,41 +362,6 @@ impl<'a> CompletionContext<'a> {
362362
FamousDefs(&self.sema, self.krate)
363363
}
364364

365-
// FIXME: This shouldn't exist
366-
pub(super) fn nameref_ctx(&self) -> Option<&NameRefContext> {
367-
match &self.ident_ctx {
368-
IdentContext::NameRef(it) => Some(it),
369-
_ => None,
370-
}
371-
}
372-
373-
// FIXME: This shouldn't exist
374-
pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
375-
match self.nameref_ctx() {
376-
Some(NameRefContext {
377-
kind: Some(NameRefKind::DotAccess(DotAccess { receiver, .. })),
378-
..
379-
}) => receiver.as_ref(),
380-
_ => None,
381-
}
382-
}
383-
384-
// FIXME: This shouldn't exist
385-
pub(crate) fn path_context(&self) -> Option<&PathCompletionCtx> {
386-
self.nameref_ctx().and_then(|ctx| match &ctx.kind {
387-
Some(NameRefKind::Path(path)) => Some(path),
388-
_ => None,
389-
})
390-
}
391-
392-
// FIXME: This shouldn't exist
393-
pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
394-
self.path_context().and_then(|it| match &it.qualified {
395-
Qualified::With { path, .. } => Some(path),
396-
_ => None,
397-
})
398-
}
399-
400365
/// Checks if an item is visible and not `doc(hidden)` at the completion site.
401366
pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
402367
where

crates/ide-completion/src/context/analysis.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,12 @@ impl<'a> CompletionContext<'a> {
430430
let (nameref_ctx, pat_ctx, qualifier_ctx) =
431431
Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone());
432432

433+
if !matches!(nameref_ctx.kind, Some(NameRefKind::Path(_))) {
434+
// FIXME: Pattern context should probably be part of ident_ctx
435+
self.pattern_ctx = pat_ctx;
436+
}
433437
self.qualifier_ctx = qualifier_ctx;
434438
self.ident_ctx = IdentContext::NameRef(nameref_ctx);
435-
self.pattern_ctx = pat_ctx;
436439
}
437440
ast::NameLike::Name(name) => {
438441
let (name_ctx, pat_ctx) = Self::classify_name(&self.sema, original_file, name)?;

crates/ide-completion/src/lib.rs

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ mod render;
1010
mod tests;
1111
mod snippet;
1212

13-
use completions::flyimport::position_for_import;
1413
use ide_db::{
1514
base_db::FilePosition,
1615
helpers::mod_path_to_ast,
@@ -25,11 +24,7 @@ use text_edit::TextEdit;
2524

2625
use crate::{
2726
completions::Completions,
28-
context::{
29-
CompletionContext,
30-
IdentContext::{self, NameRef},
31-
NameRefContext, NameRefKind,
32-
},
27+
context::{CompletionContext, IdentContext, NameRefContext, NameRefKind},
3328
};
3429

3530
pub use crate::{
@@ -156,8 +151,10 @@ pub fn completions(
156151

157152
// prevent `(` from triggering unwanted completion noise
158153
if trigger_character == Some('(') {
159-
if let NameRef(NameRefContext { kind: Some(NameRefKind::Path(path_ctx)), .. }) =
160-
&ctx.ident_ctx
154+
if let IdentContext::NameRef(NameRefContext {
155+
kind: Some(NameRefKind::Path(path_ctx)),
156+
..
157+
}) = &ctx.ident_ctx
161158
{
162159
completions::vis::complete_vis_path(&mut completions, ctx, path_ctx);
163160
}
@@ -171,16 +168,18 @@ pub fn completions(
171168
match &ctx.ident_ctx {
172169
IdentContext::Name(name_ctx) => {
173170
completions::field::complete_field_list_record_variant(acc, ctx, name_ctx);
174-
completions::mod_::complete_mod(acc, ctx, name_ctx);
175171
completions::item_list::trait_impl::complete_trait_impl_name(acc, ctx, name_ctx);
172+
completions::mod_::complete_mod(acc, ctx, name_ctx);
176173
}
177-
NameRef(name_ref_ctx @ NameRefContext { kind, .. }) => {
174+
IdentContext::NameRef(name_ref_ctx @ NameRefContext { kind, .. }) => {
178175
completions::expr::complete_expr_path(acc, ctx, name_ref_ctx);
179176
completions::field::complete_field_list_tuple_variant(acc, ctx, name_ref_ctx);
180-
completions::use_::complete_use_tree(acc, ctx, name_ref_ctx);
181177
completions::item_list::complete_item_list(acc, ctx, name_ref_ctx);
178+
completions::use_::complete_use_tree(acc, ctx, name_ref_ctx);
179+
182180
match kind {
183181
Some(NameRefKind::Path(path_ctx)) => {
182+
completions::flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
184183
completions::record::complete_record_expr_func_update(acc, ctx, path_ctx);
185184
completions::attribute::complete_attribute(acc, ctx, path_ctx);
186185
completions::attribute::complete_derive(acc, ctx, path_ctx);
@@ -193,6 +192,7 @@ pub fn completions(
193192
completions::vis::complete_vis_path(acc, ctx, path_ctx);
194193
}
195194
Some(NameRefKind::DotAccess(dot_access)) => {
195+
completions::flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
196196
completions::dot::complete_dot(acc, ctx, dot_access);
197197
completions::postfix::complete_postfix(acc, ctx, dot_access);
198198
}
@@ -224,19 +224,11 @@ pub fn completions(
224224
}
225225

226226
if let Some(pattern_ctx) = &ctx.pattern_ctx {
227+
completions::flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
227228
completions::fn_param::complete_fn_param(acc, ctx, pattern_ctx);
229+
completions::pattern::complete_pattern(acc, ctx, pattern_ctx);
228230
completions::record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
229-
// FIXME: this check is odd, we shouldn't need this?
230-
if !matches!(
231-
ctx.ident_ctx,
232-
IdentContext::NameRef(NameRefContext { kind: Some(NameRefKind::Path(_)), .. })
233-
) {
234-
completions::pattern::complete_pattern(acc, ctx, pattern_ctx);
235-
}
236231
}
237-
238-
// FIXME: This should be split
239-
completions::flyimport::import_on_the_fly(acc, ctx);
240232
}
241233

242234
Some(completions)
@@ -252,7 +244,7 @@ pub fn resolve_completion_edits(
252244
) -> Option<Vec<TextEdit>> {
253245
let _p = profile::span("resolve_completion_edits");
254246
let ctx = CompletionContext::new(db, position, config)?;
255-
let position_for_import = &position_for_import(&ctx, None)?;
247+
let position_for_import = &ctx.original_token.parent()?;
256248
let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
257249

258250
let current_module = ctx.sema.scope(position_for_import)?.module();

0 commit comments

Comments
 (0)