Skip to content

Commit 441e659

Browse files
committed
Complete associated type only in trait generic arg
Fix tidy check does not work for marks in multiline
1 parent e1a8c0b commit 441e659

File tree

3 files changed

+119
-63
lines changed

3 files changed

+119
-63
lines changed

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

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,39 +120,64 @@ pub(crate) fn complete_type_path(
120120
}
121121
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
122122
Qualified::No => {
123-
acc.add_nameref_keywords_with_colon(ctx);
124-
if let TypeLocation::TypeBound = location {
125-
ctx.process_all_names(&mut |name, res| {
126-
let add_resolution = match res {
127-
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
128-
ScopeDef::ModuleDef(
129-
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
130-
) => true,
131-
_ => false,
132-
};
133-
if add_resolution {
134-
acc.add_path_resolution(ctx, path_ctx, name, res);
135-
}
136-
});
137-
return;
138-
}
139-
if let TypeLocation::GenericArgList(Some(arg_list)) = location {
140-
if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast)
141-
{
142-
if path_seg.syntax().ancestors().find_map(ast::TypeBound::cast).is_some() {
143-
if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
144-
ctx.sema.resolve_path(&path_seg.parent_path())
145-
{
146-
trait_.items_with_supertraits(ctx.sema.db).into_iter().for_each(|it| {
147-
if let hir::AssocItem::TypeAlias(alias) = it {
148-
cov_mark::hit!(complete_assoc_type_in_generics_list);
149-
acc.add_type_alias_with_eq(ctx, alias)
123+
match location {
124+
TypeLocation::TypeBound => {
125+
acc.add_nameref_keywords_with_colon(ctx);
126+
ctx.process_all_names(&mut |name, res| {
127+
let add_resolution = match res {
128+
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
129+
mac.is_fn_like(ctx.db)
130+
}
131+
ScopeDef::ModuleDef(
132+
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
133+
) => true,
134+
_ => false,
135+
};
136+
if add_resolution {
137+
acc.add_path_resolution(ctx, path_ctx, name, res);
138+
}
139+
});
140+
return;
141+
}
142+
TypeLocation::GenericArgList(Some(arg_list)) => {
143+
match arg_list.generic_args().next() {
144+
Some(ast::GenericArg::AssocTypeArg(_)) => {}
145+
_ => {
146+
if let Some(path_seg) =
147+
arg_list.syntax().parent().and_then(ast::PathSegment::cast)
148+
{
149+
if path_seg
150+
.syntax()
151+
.ancestors()
152+
.find_map(ast::TypeBound::cast)
153+
.is_some()
154+
{
155+
if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(
156+
trait_,
157+
))) = ctx.sema.resolve_path(&path_seg.parent_path())
158+
{
159+
trait_
160+
.items_with_supertraits(ctx.sema.db)
161+
.into_iter()
162+
.for_each(|it| {
163+
if let hir::AssocItem::TypeAlias(alias) = it {
164+
cov_mark::hit!(
165+
complete_assoc_type_in_generics_list
166+
);
167+
acc.add_type_alias_with_eq(ctx, alias);
168+
}
169+
});
170+
return; // only AssocTypeArgs make sense
171+
}
150172
}
151-
});
173+
}
152174
}
153175
}
154176
}
155-
}
177+
_ => {}
178+
};
179+
180+
acc.add_nameref_keywords_with_colon(ctx);
156181
ctx.process_all_names(&mut |name, def| {
157182
if scope_def_applicable(def) {
158183
acc.add_path_resolution(ctx, path_ctx, name, def);

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

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -380,25 +380,8 @@ trait Trait2: Trait1 {
380380
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
381381
"#,
382382
expect![[r#"
383-
ct CONST
384-
cp CONST_PARAM
385-
en Enum
386-
ma makro!(…) macro_rules! makro
387-
md module
388-
st Record
389-
st Tuple
390-
st Unit
391-
tt Trait
392-
tt Trait1
393-
tt Trait2
394383
ta Foo = (as Trait2) type Foo
395384
ta Super = (as Trait1) type Super
396-
tp T
397-
un Union
398-
bt u32
399-
kw crate::
400-
kw self::
401-
kw super::
402385
"#]],
403386
);
404387
check(
@@ -472,3 +455,48 @@ fn func(_: Enum::$0) {}
472455
"#]],
473456
);
474457
}
458+
459+
#[test]
460+
fn completes_associated_type_only() {
461+
check(
462+
r#"
463+
trait MyTrait {
464+
type Item;
465+
};
466+
467+
fn f(t: impl MyTrait<I$0
468+
"#,
469+
expect![[r#"
470+
ta Item = (as MyTrait) type Item
471+
"#]],
472+
);
473+
}
474+
475+
#[test]
476+
fn completes_types_after_associated_type() {
477+
check(
478+
r#"
479+
trait MyTrait {
480+
type Item;
481+
};
482+
483+
fn f(t: impl MyTrait<Item = $0
484+
"#,
485+
expect![[r#"
486+
ct CONST
487+
en Enum
488+
ma makro!(…) macro_rules! makro
489+
md module
490+
st Record
491+
st Tuple
492+
st Unit
493+
tt MyTrait
494+
tt Trait
495+
un Union
496+
bt u32
497+
kw crate::
498+
kw self::
499+
kw super::
500+
"#]],
501+
);
502+
}

crates/rust-analyzer/tests/slow-tests/tidy.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -471,17 +471,9 @@ struct TidyMarks {
471471

472472
impl TidyMarks {
473473
fn visit(&mut self, _path: &Path, text: &str) {
474-
for line in text.lines() {
475-
if let Some(mark) = find_mark(line, "hit") {
476-
self.hits.insert(mark.to_string());
477-
}
478-
if let Some(mark) = find_mark(line, "check") {
479-
self.checks.insert(mark.to_string());
480-
}
481-
if let Some(mark) = find_mark(line, "check_count") {
482-
self.checks.insert(mark.to_string());
483-
}
484-
}
474+
find_marks(&mut self.hits, text, "hit");
475+
find_marks(&mut self.checks, text, "check");
476+
find_marks(&mut self.checks, text, "check_count");
485477
}
486478

487479
fn finish(self) {
@@ -506,10 +498,21 @@ fn stable_hash(text: &str) -> u64 {
506498
hasher.finish()
507499
}
508500

509-
fn find_mark<'a>(text: &'a str, mark: &'static str) -> Option<&'a str> {
510-
let idx = text.find(mark)?;
511-
let text = text[idx + mark.len()..].strip_prefix("!(")?;
512-
let idx = text.find(|c: char| !(c.is_alphanumeric() || c == '_'))?;
513-
let text = &text[..idx];
514-
Some(text)
501+
fn find_marks(set: &mut HashSet<String>, text: &str, mark: &str) {
502+
let mut text = text;
503+
let mut prev_text = "";
504+
while text != prev_text {
505+
prev_text = text;
506+
if let Some(idx) = text.find(mark) {
507+
text = &text[idx + mark.len()..];
508+
if let Some(stripped_text) = text.strip_prefix("!(") {
509+
text = stripped_text.trim_start();
510+
if let Some(idx2) = text.find(|c: char| !(c.is_alphanumeric() || c == '_')) {
511+
let mark_text = &text[..idx2];
512+
set.insert(mark_text.to_string());
513+
text = &text[idx2..];
514+
}
515+
}
516+
}
517+
}
515518
}

0 commit comments

Comments
 (0)