Skip to content

Commit d7b30a5

Browse files
committed
Add self param completions for trait assoc fn
Example --- ```rust trait A { fn foo(file_id: usize) {} fn new($0) {} } ``` **Before this PR**: ```text bn file_id: usize kw mut kw ref ``` **After this PR**: ```text bn &mut self bn &self bn file_id: usize bn mut self bn self kw mut kw ref ```
1 parent 2936257 commit d7b30a5

File tree

7 files changed

+65
-18
lines changed

7 files changed

+65
-18
lines changed

crates/ide-completion/src/completions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ fn enum_variants_with_paths(
630630
acc: &mut Completions,
631631
ctx: &CompletionContext<'_>,
632632
enum_: hir::Enum,
633-
impl_: &Option<ast::Impl>,
633+
impl_: Option<&ast::Impl>,
634634
cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
635635
) {
636636
let mut process_variant = |variant: Variant| {
@@ -644,7 +644,7 @@ fn enum_variants_with_paths(
644644

645645
let variants = enum_.variants(ctx.db);
646646

647-
if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_))
647+
if let Some(impl_) = impl_.and_then(|impl_| ctx.sema.to_def(impl_))
648648
&& impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_))
649649
{
650650
variants.iter().for_each(|variant| process_variant(*variant));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ pub(crate) fn complete_expr_path(
297297
acc,
298298
ctx,
299299
e,
300-
impl_,
300+
impl_.as_ref(),
301301
|acc, ctx, variant, path| {
302302
acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
303303
},

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use hir::HirDisplay;
44
use ide_db::FxHashMap;
5+
use itertools::Either;
56
use syntax::{
67
AstNode, Direction, SyntaxKind, TextRange, TextSize, algo,
78
ast::{self, HasModuleItem},
@@ -24,8 +25,8 @@ pub(crate) fn complete_fn_param(
2425
ctx: &CompletionContext<'_>,
2526
pattern_ctx: &PatternContext,
2627
) -> Option<()> {
27-
let (ParamContext { param_list, kind, .. }, impl_) = match pattern_ctx {
28-
PatternContext { param_ctx: Some(kind), impl_, .. } => (kind, impl_),
28+
let (ParamContext { param_list, kind, .. }, impl_or_trait) = match pattern_ctx {
29+
PatternContext { param_ctx: Some(kind), impl_or_trait, .. } => (kind, impl_or_trait),
2930
_ => return None,
3031
};
3132

@@ -45,7 +46,7 @@ pub(crate) fn complete_fn_param(
4546

4647
match kind {
4748
ParamKind::Function(function) => {
48-
fill_fn_params(ctx, function, param_list, impl_, add_new_item_to_acc);
49+
fill_fn_params(ctx, function, param_list, impl_or_trait, add_new_item_to_acc);
4950
}
5051
ParamKind::Closure(closure) => {
5152
let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?;
@@ -62,7 +63,7 @@ fn fill_fn_params(
6263
ctx: &CompletionContext<'_>,
6364
function: &ast::Fn,
6465
param_list: &ast::ParamList,
65-
impl_: &Option<ast::Impl>,
66+
impl_or_trait: &Option<Either<ast::Impl, ast::Trait>>,
6667
mut add_new_item_to_acc: impl FnMut(&str),
6768
) {
6869
let mut file_params = FxHashMap::default();
@@ -107,7 +108,7 @@ fn fill_fn_params(
107108
}
108109
remove_duplicated(&mut file_params, param_list.params());
109110
let self_completion_items = ["self", "&self", "mut self", "&mut self"];
110-
if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_) {
111+
if should_add_self_completions(ctx.token.text_range().start(), param_list, impl_or_trait) {
111112
self_completion_items.into_iter().for_each(&mut add_new_item_to_acc);
112113
}
113114

@@ -161,9 +162,9 @@ fn remove_duplicated(
161162
fn should_add_self_completions(
162163
cursor: TextSize,
163164
param_list: &ast::ParamList,
164-
impl_: &Option<ast::Impl>,
165+
impl_or_trait: &Option<Either<ast::Impl, ast::Trait>>,
165166
) -> bool {
166-
if impl_.is_none() || param_list.self_param().is_some() {
167+
if impl_or_trait.is_none() || param_list.self_param().is_some() {
167168
return false;
168169
}
169170
match param_list.params().next() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub(crate) fn complete_pattern(
7070
acc,
7171
ctx,
7272
e,
73-
&pattern_ctx.impl_,
73+
pattern_ctx.impl_or_trait.as_ref().and_then(|it| it.as_ref().left()),
7474
|acc, ctx, variant, path| {
7575
acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
7676
},

crates/ide-completion/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use ide_db::{
1515
FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
1616
helpers::is_editable_crate,
1717
};
18+
use itertools::Either;
1819
use syntax::{
1920
AstNode, Edition, SmolStr,
2021
SyntaxKind::{self, *},
@@ -282,7 +283,7 @@ pub(crate) struct PatternContext {
282283
pub(crate) mut_token: Option<SyntaxToken>,
283284
/// The record pattern this name or ref is a field of
284285
pub(crate) record_pat: Option<ast::RecordPat>,
285-
pub(crate) impl_: Option<ast::Impl>,
286+
pub(crate) impl_or_trait: Option<Either<ast::Impl, ast::Trait>>,
286287
/// List of missing variants in a match expr
287288
pub(crate) missing_variants: Vec<hir::Variant>,
288289
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,8 @@ fn classify_name_ref<'db>(
13021302
.is_some_and(|it| it.semicolon_token().is_none())
13031303
|| after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
13041304
let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
1305-
let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
1305+
let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax())
1306+
.and_then(Either::left);
13061307

13071308
let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) {
13081309
Some(arm) => arm
@@ -1755,27 +1756,29 @@ fn pattern_context_for(
17551756
mut_token,
17561757
ref_token,
17571758
record_pat: None,
1758-
impl_: fetch_immediate_impl(sema, original_file, pat.syntax()),
1759+
impl_or_trait: fetch_immediate_impl_or_trait(sema, original_file, pat.syntax()),
17591760
missing_variants,
17601761
}
17611762
}
17621763

1763-
fn fetch_immediate_impl(
1764+
fn fetch_immediate_impl_or_trait(
17641765
sema: &Semantics<'_, RootDatabase>,
17651766
original_file: &SyntaxNode,
17661767
node: &SyntaxNode,
1767-
) -> Option<ast::Impl> {
1768+
) -> Option<Either<ast::Impl, ast::Trait>> {
17681769
let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)?
17691770
.filter_map(ast::Item::cast)
17701771
.filter(|it| !matches!(it, ast::Item::MacroCall(_)));
17711772

17721773
match ancestors.next()? {
17731774
ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (),
1774-
ast::Item::Impl(it) => return Some(it),
1775+
ast::Item::Impl(it) => return Some(Either::Left(it)),
1776+
ast::Item::Trait(it) => return Some(Either::Right(it)),
17751777
_ => return None,
17761778
}
17771779
match ancestors.next()? {
1778-
ast::Item::Impl(it) => Some(it),
1780+
ast::Item::Impl(it) => return Some(Either::Left(it)),
1781+
ast::Item::Trait(it) => return Some(Either::Right(it)),
17791782
_ => None,
17801783
}
17811784
}

crates/ide-completion/src/tests/fn_param.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ pub(crate) trait SourceRoot {
8585
}
8686
"#,
8787
expect![[r#"
88+
bn &mut self
89+
bn &self
8890
bn file_id: usize
91+
bn mut self
92+
bn self
8993
kw mut
9094
kw ref
9195
"#]],
@@ -183,6 +187,44 @@ impl A {
183187
)
184188
}
185189

190+
#[test]
191+
fn in_trait_only_param() {
192+
check(
193+
r#"
194+
trait A {
195+
fn foo(file_id: usize) {}
196+
fn new($0) {}
197+
}
198+
"#,
199+
expect![[r#"
200+
bn &mut self
201+
bn &self
202+
bn file_id: usize
203+
bn mut self
204+
bn self
205+
kw mut
206+
kw ref
207+
"#]],
208+
)
209+
}
210+
211+
#[test]
212+
fn in_trait_after_self() {
213+
check(
214+
r#"
215+
trait A {
216+
fn foo(file_id: usize) {}
217+
fn new(self, $0) {}
218+
}
219+
"#,
220+
expect![[r#"
221+
bn file_id: usize
222+
kw mut
223+
kw ref
224+
"#]],
225+
)
226+
}
227+
186228
// doesn't complete qux due to there being no expression after
187229
// see source_analyzer::adjust comment
188230
#[test]

0 commit comments

Comments
 (0)