Skip to content

Commit 748a8ce

Browse files
bors[bot]oxalica
andauthored
Merge #6010
6010: Avoid checking all ancestors and fix mis-completion r=jonas-schievink a=oxalica Refactor the logic of `completion_match` to check deterministic number of ancestors instead of `token.ancestors().find_map()`. This should fix wrong completions (#5976 (comment)) and hopefully make completion to be faster (#6004). More play and test? @jonas-schievink @hammypants If this patch works, we can avoid the revert #6005 . 😞 Co-authored-by: oxalica <[email protected]>
2 parents 37f3b9c + d2fced1 commit 748a8ce

File tree

1 file changed

+215
-33
lines changed

1 file changed

+215
-33
lines changed

crates/ide/src/completion/complete_trait_impl.rs

Lines changed: 215 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -86,36 +86,46 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt
8686
token = token.prev_token()?;
8787
}
8888

89-
let (kind, trigger, impl_def_offset) = token.ancestors().find_map(|p| match p.kind() {
90-
// `const` can be a modifier of an item, so the `const` token may be inside another item syntax node.
91-
// Eg. `impl .. { const <|> fn bar() .. }`
92-
SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST
93-
if token.kind() == SyntaxKind::CONST_KW =>
94-
{
95-
Some((ImplCompletionKind::Const, p, 2))
96-
}
97-
SyntaxKind::FN => Some((ImplCompletionKind::Fn, p, 2)),
98-
SyntaxKind::TYPE_ALIAS => Some((ImplCompletionKind::TypeAlias, p, 2)),
99-
SyntaxKind::CONST => Some((ImplCompletionKind::Const, p, 2)),
100-
// `impl .. { const <|> }` is parsed as:
101-
// IMPL
102-
// ASSOC_ITEM_LIST
103-
// ERROR
104-
// CONST_KW <- token
105-
// WHITESPACE <- ctx.token
106-
SyntaxKind::ERROR
107-
if p.first_token().map_or(false, |t| t.kind() == SyntaxKind::CONST_KW) =>
108-
{
109-
Some((ImplCompletionKind::Const, p, 2))
110-
}
111-
SyntaxKind::NAME_REF => Some((ImplCompletionKind::All, p, 5)),
112-
_ => None,
113-
})?;
89+
let impl_item_offset = match token.kind() {
90+
// `impl .. { const <|> }`
91+
// ERROR 0
92+
// CONST_KW <- *
93+
SyntaxKind::CONST_KW => 0,
94+
// `impl .. { fn/type <|> }`
95+
// FN/TYPE_ALIAS 0
96+
// FN_KW <- *
97+
SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0,
98+
// `impl .. { fn/type/const foo<|> }`
99+
// FN/TYPE_ALIAS/CONST 1
100+
// NAME 0
101+
// IDENT <- *
102+
SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1,
103+
// `impl .. { foo<|> }`
104+
// MACRO_CALL 3
105+
// PATH 2
106+
// PATH_SEGMENT 1
107+
// NAME_REF 0
108+
// IDENT <- *
109+
SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME_REF => 3,
110+
_ => return None,
111+
};
114112

115-
let impl_def = (0..impl_def_offset - 1)
116-
.try_fold(trigger.parent()?, |t, _| t.parent())
117-
.and_then(ast::Impl::cast)?;
118-
Some((kind, trigger, impl_def))
113+
let impl_item = token.ancestors().nth(impl_item_offset)?;
114+
// Must directly belong to an impl block.
115+
// IMPL
116+
// ASSOC_ITEM_LIST
117+
// <item>
118+
let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
119+
let kind = match impl_item.kind() {
120+
// `impl ... { const <|> fn/type/const }`
121+
_ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const,
122+
SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
123+
SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
124+
SyntaxKind::FN => ImplCompletionKind::Fn,
125+
SyntaxKind::MACRO_CALL => ImplCompletionKind::All,
126+
_ => return None,
127+
};
128+
Some((kind, impl_item, impl_def))
119129
}
120130

121131
fn add_function_impl(
@@ -261,19 +271,191 @@ ta type TestType = \n\
261271
}
262272

263273
#[test]
264-
fn no_nested_fn_completions() {
274+
fn no_completion_inside_fn() {
265275
check(
266276
r"
267-
trait Test {
268-
fn test();
269-
fn test2();
277+
trait Test { fn test(); fn test2(); }
278+
struct T;
279+
280+
impl Test for T {
281+
fn test() {
282+
t<|>
283+
}
284+
}
285+
",
286+
expect![[""]],
287+
);
288+
289+
check(
290+
r"
291+
trait Test { fn test(); fn test2(); }
292+
struct T;
293+
294+
impl Test for T {
295+
fn test() {
296+
fn t<|>
297+
}
270298
}
299+
",
300+
expect![[""]],
301+
);
302+
303+
check(
304+
r"
305+
trait Test { fn test(); fn test2(); }
271306
struct T;
272307
273308
impl Test for T {
274309
fn test() {
310+
fn <|>
311+
}
312+
}
313+
",
314+
expect![[""]],
315+
);
316+
317+
// https://github.com/rust-analyzer/rust-analyzer/pull/5976#issuecomment-692332191
318+
check(
319+
r"
320+
trait Test { fn test(); fn test2(); }
321+
struct T;
322+
323+
impl Test for T {
324+
fn test() {
325+
foo.<|>
326+
}
327+
}
328+
",
329+
expect![[""]],
330+
);
331+
332+
check(
333+
r"
334+
trait Test { fn test(_: i32); fn test2(); }
335+
struct T;
336+
337+
impl Test for T {
338+
fn test(t<|>)
339+
}
340+
",
341+
expect![[""]],
342+
);
343+
344+
check(
345+
r"
346+
trait Test { fn test(_: fn()); fn test2(); }
347+
struct T;
348+
349+
impl Test for T {
350+
fn test(f: fn <|>)
351+
}
352+
",
353+
expect![[""]],
354+
);
355+
}
356+
357+
#[test]
358+
fn no_completion_inside_const() {
359+
check(
360+
r"
361+
trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
362+
struct T;
363+
364+
impl Test for T {
365+
const TEST: fn <|>
366+
}
367+
",
368+
expect![[""]],
369+
);
370+
371+
check(
372+
r"
373+
trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
374+
struct T;
375+
376+
impl Test for T {
377+
const TEST: T<|>
378+
}
379+
",
380+
expect![[""]],
381+
);
382+
383+
check(
384+
r"
385+
trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
386+
struct T;
387+
388+
impl Test for T {
389+
const TEST: u32 = f<|>
390+
}
391+
",
392+
expect![[""]],
393+
);
394+
395+
check(
396+
r"
397+
trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
398+
struct T;
399+
400+
impl Test for T {
401+
const TEST: u32 = {
275402
t<|>
403+
};
404+
}
405+
",
406+
expect![[""]],
407+
);
408+
409+
check(
410+
r"
411+
trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
412+
struct T;
413+
414+
impl Test for T {
415+
const TEST: u32 = {
416+
fn <|>
417+
};
418+
}
419+
",
420+
expect![[""]],
421+
);
422+
423+
check(
424+
r"
425+
trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
426+
struct T;
427+
428+
impl Test for T {
429+
const TEST: u32 = {
430+
fn t<|>
431+
};
432+
}
433+
",
434+
expect![[""]],
435+
);
276436
}
437+
438+
#[test]
439+
fn no_completion_inside_type() {
440+
check(
441+
r"
442+
trait Test { type Test; type Test2; fn test(); }
443+
struct T;
444+
445+
impl Test for T {
446+
type Test = T<|>;
447+
}
448+
",
449+
expect![[""]],
450+
);
451+
452+
check(
453+
r"
454+
trait Test { type Test; type Test2; fn test(); }
455+
struct T;
456+
457+
impl Test for T {
458+
type Test = fn <|>;
277459
}
278460
",
279461
expect![[""]],

0 commit comments

Comments
 (0)