Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 98c0578

Browse files
committed
Move trait_impl completion analysis into CompletionContext
1 parent 2a60b84 commit 98c0578

File tree

5 files changed

+186
-183
lines changed

5 files changed

+186
-183
lines changed

crates/ide-completion/src/completions.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ pub(crate) mod pattern;
1616
pub(crate) mod postfix;
1717
pub(crate) mod record;
1818
pub(crate) mod snippet;
19-
pub(crate) mod trait_impl;
2019
pub(crate) mod r#type;
2120
pub(crate) mod use_;
2221
pub(crate) mod vis;

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ use crate::{
66
CompletionContext, Completions,
77
};
88

9+
mod trait_impl;
10+
911
pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
1012
let _p = profile::span("complete_item_list");
1113

14+
if let Some(_) = ctx.name_ctx() {
15+
trait_impl::complete_trait_impl(acc, ctx);
16+
return;
17+
}
18+
1219
let (&is_absolute_path, path_qualifier, kind) = match ctx.path_context() {
1320
Some(PathCompletionCtx {
1421
kind: PathKind::Item { kind },
@@ -24,7 +31,6 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
2431
}) => (is_absolute_path, qualifier, None),
2532
_ => return,
2633
};
27-
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
2834

2935
let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
3036
let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
@@ -35,6 +41,11 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
3541
let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
3642
let in_block = matches!(kind, None);
3743

44+
if in_trait_impl {
45+
trait_impl::complete_trait_impl(acc, ctx);
46+
}
47+
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
48+
3849
'block: loop {
3950
if ctx.is_non_trivial_path() {
4051
break 'block;

crates/ide-completion/src/completions/trait_impl.rs renamed to crates/ide-completion/src/completions/item_list/trait_impl.rs

Lines changed: 37 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use syntax::{
4343
use text_edit::TextEdit;
4444

4545
use crate::{
46+
context::{ItemListKind, NameContext, NameKind, NameRefContext, PathCompletionCtx, PathKind},
4647
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
4748
};
4849

@@ -54,7 +55,6 @@ enum ImplCompletionKind {
5455
Const,
5556
}
5657

57-
// FIXME: Make this a submodule of [`item_list`]
5858
pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
5959
if let Some((kind, replacement_range, impl_def)) = completion_match(ctx) {
6060
if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
@@ -77,74 +77,48 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
7777
}
7878
}
7979

80-
// FIXME: This should be lifted out so that we can do proper smart item keyword completions
8180
fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, TextRange, ast::Impl)> {
8281
let token = ctx.token.clone();
8382

84-
// For keyword without name like `impl .. { fn $0 }`, the current position is inside
85-
// the whitespace token, which is outside `FN` syntax node.
86-
// We need to follow the previous token in this case.
87-
let mut token_before_ws = token.clone();
88-
if token.kind() == SyntaxKind::WHITESPACE {
89-
token_before_ws = token.prev_token()?;
90-
}
91-
92-
let parent_kind = token_before_ws.parent().map_or(SyntaxKind::EOF, |it| it.kind());
93-
if token.parent().map(|n| n.kind()) == Some(SyntaxKind::ASSOC_ITEM_LIST)
94-
&& matches!(
95-
token_before_ws.kind(),
96-
SyntaxKind::SEMICOLON | SyntaxKind::R_CURLY | SyntaxKind::L_CURLY
97-
)
98-
{
99-
let impl_def = ast::Impl::cast(token.parent()?.parent()?)?;
100-
let kind = ImplCompletionKind::All;
101-
let replacement_range = TextRange::empty(ctx.position.offset);
102-
Some((kind, replacement_range, impl_def))
103-
} else {
104-
let impl_item_offset = match token_before_ws.kind() {
105-
// `impl .. { const $0 }`
106-
// ERROR 0
107-
// CONST_KW <- *
108-
T![const] => 0,
109-
// `impl .. { fn/type $0 }`
110-
// FN/TYPE_ALIAS 0
111-
// FN_KW <- *
112-
T![fn] | T![type] => 0,
113-
// `impl .. { fn/type/const foo$0 }`
114-
// FN/TYPE_ALIAS/CONST 1
115-
// NAME 0
116-
// IDENT <- *
117-
SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME => 1,
118-
// `impl .. { foo$0 }`
119-
// MACRO_CALL 3
120-
// PATH 2
121-
// PATH_SEGMENT 1
122-
// NAME_REF 0
123-
// IDENT <- *
124-
SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME_REF => 3,
83+
if let Some(NameContext { name, kind, .. }) = ctx.name_ctx() {
84+
let kind = match kind {
85+
NameKind::Const => ImplCompletionKind::Const,
86+
NameKind::Function => ImplCompletionKind::Fn,
87+
NameKind::TypeAlias => ImplCompletionKind::TypeAlias,
12588
_ => return None,
12689
};
127-
128-
let impl_item = token_before_ws.ancestors().nth(impl_item_offset)?;
129-
// Must directly belong to an impl block.
130-
// IMPL
131-
// ASSOC_ITEM_LIST
132-
// <item>
133-
let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
134-
let kind = match impl_item.kind() {
135-
// `impl ... { const $0 fn/type/const }`
136-
_ if token_before_ws.kind() == T![const] => ImplCompletionKind::Const,
137-
SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
138-
SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
139-
SyntaxKind::FN => ImplCompletionKind::Fn,
140-
SyntaxKind::MACRO_CALL => ImplCompletionKind::All,
141-
_ => return None,
142-
};
143-
144-
let replacement_range = replacement_range(ctx, &impl_item);
145-
146-
Some((kind, replacement_range, impl_def))
90+
let item = match name {
91+
Some(name) => name.syntax().parent(),
92+
None => {
93+
if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
94+
.parent()
95+
}
96+
}?;
97+
return Some((
98+
kind,
99+
replacement_range(ctx, &item),
100+
// item -> ASSOC_ITEM_LIST -> IMPL
101+
ast::Impl::cast(item.parent()?.parent()?)?,
102+
));
103+
} else if let Some(NameRefContext {
104+
nameref,
105+
path_ctx:
106+
Some(PathCompletionCtx { kind: PathKind::Item { kind: ItemListKind::TraitImpl }, .. }),
107+
..
108+
}) = ctx.nameref_ctx()
109+
{
110+
if !ctx.is_non_trivial_path() {
111+
return Some((
112+
ImplCompletionKind::All,
113+
match nameref {
114+
Some(name) => name.syntax().text_range(),
115+
None => TextRange::empty(ctx.position.offset),
116+
},
117+
ctx.impl_def.clone()?,
118+
));
119+
}
147120
}
121+
None
148122
}
149123

150124
fn add_function_impl(

0 commit comments

Comments
 (0)