mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Complete associated type only in trait generic arg
Fix tidy check does not work for marks in multiline
This commit is contained in:
parent
e1a8c0b153
commit
441e659aa1
@ -120,39 +120,64 @@ pub(crate) fn complete_type_path(
|
||||
}
|
||||
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
|
||||
Qualified::No => {
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
if let TypeLocation::TypeBound = location {
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
let add_resolution = match res {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
|
||||
ScopeDef::ModuleDef(
|
||||
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
|
||||
) => true,
|
||||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_path_resolution(ctx, path_ctx, name, res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if let TypeLocation::GenericArgList(Some(arg_list)) = location {
|
||||
if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast)
|
||||
{
|
||||
if path_seg.syntax().ancestors().find_map(ast::TypeBound::cast).is_some() {
|
||||
if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
|
||||
ctx.sema.resolve_path(&path_seg.parent_path())
|
||||
{
|
||||
trait_.items_with_supertraits(ctx.sema.db).into_iter().for_each(|it| {
|
||||
if let hir::AssocItem::TypeAlias(alias) = it {
|
||||
cov_mark::hit!(complete_assoc_type_in_generics_list);
|
||||
acc.add_type_alias_with_eq(ctx, alias)
|
||||
match location {
|
||||
TypeLocation::TypeBound => {
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
let add_resolution = match res {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
|
||||
mac.is_fn_like(ctx.db)
|
||||
}
|
||||
ScopeDef::ModuleDef(
|
||||
hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
|
||||
) => true,
|
||||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_path_resolution(ctx, path_ctx, name, res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
TypeLocation::GenericArgList(Some(arg_list)) => {
|
||||
match arg_list.generic_args().next() {
|
||||
Some(ast::GenericArg::AssocTypeArg(_)) => {}
|
||||
_ => {
|
||||
if let Some(path_seg) =
|
||||
arg_list.syntax().parent().and_then(ast::PathSegment::cast)
|
||||
{
|
||||
if path_seg
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.find_map(ast::TypeBound::cast)
|
||||
.is_some()
|
||||
{
|
||||
if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(
|
||||
trait_,
|
||||
))) = ctx.sema.resolve_path(&path_seg.parent_path())
|
||||
{
|
||||
trait_
|
||||
.items_with_supertraits(ctx.sema.db)
|
||||
.into_iter()
|
||||
.for_each(|it| {
|
||||
if let hir::AssocItem::TypeAlias(alias) = it {
|
||||
cov_mark::hit!(
|
||||
complete_assoc_type_in_generics_list
|
||||
);
|
||||
acc.add_type_alias_with_eq(ctx, alias);
|
||||
}
|
||||
});
|
||||
return; // only AssocTypeArgs make sense
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
ctx.process_all_names(&mut |name, def| {
|
||||
if scope_def_applicable(def) {
|
||||
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||
|
@ -380,25 +380,8 @@ trait Trait2: Trait1 {
|
||||
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST
|
||||
cp CONST_PARAM
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
tt Trait
|
||||
tt Trait1
|
||||
tt Trait2
|
||||
ta Foo = (as Trait2) type Foo
|
||||
ta Super = (as Trait1) type Super
|
||||
tp T
|
||||
un Union
|
||||
bt u32
|
||||
kw crate::
|
||||
kw self::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
@ -472,3 +455,48 @@ fn func(_: Enum::$0) {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_associated_type_only() {
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait {
|
||||
type Item;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<I$0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ta Item = (as MyTrait) type Item
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_types_after_associated_type() {
|
||||
check(
|
||||
r#"
|
||||
trait MyTrait {
|
||||
type Item;
|
||||
};
|
||||
|
||||
fn f(t: impl MyTrait<Item = $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct CONST
|
||||
en Enum
|
||||
ma makro!(…) macro_rules! makro
|
||||
md module
|
||||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
tt MyTrait
|
||||
tt Trait
|
||||
un Union
|
||||
bt u32
|
||||
kw crate::
|
||||
kw self::
|
||||
kw super::
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -471,17 +471,9 @@ struct TidyMarks {
|
||||
|
||||
impl TidyMarks {
|
||||
fn visit(&mut self, _path: &Path, text: &str) {
|
||||
for line in text.lines() {
|
||||
if let Some(mark) = find_mark(line, "hit") {
|
||||
self.hits.insert(mark.to_string());
|
||||
}
|
||||
if let Some(mark) = find_mark(line, "check") {
|
||||
self.checks.insert(mark.to_string());
|
||||
}
|
||||
if let Some(mark) = find_mark(line, "check_count") {
|
||||
self.checks.insert(mark.to_string());
|
||||
}
|
||||
}
|
||||
find_marks(&mut self.hits, text, "hit");
|
||||
find_marks(&mut self.checks, text, "check");
|
||||
find_marks(&mut self.checks, text, "check_count");
|
||||
}
|
||||
|
||||
fn finish(self) {
|
||||
@ -506,10 +498,21 @@ fn stable_hash(text: &str) -> u64 {
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
fn find_mark<'a>(text: &'a str, mark: &'static str) -> Option<&'a str> {
|
||||
let idx = text.find(mark)?;
|
||||
let text = text[idx + mark.len()..].strip_prefix("!(")?;
|
||||
let idx = text.find(|c: char| !(c.is_alphanumeric() || c == '_'))?;
|
||||
let text = &text[..idx];
|
||||
Some(text)
|
||||
fn find_marks(set: &mut HashSet<String>, text: &str, mark: &str) {
|
||||
let mut text = text;
|
||||
let mut prev_text = "";
|
||||
while text != prev_text {
|
||||
prev_text = text;
|
||||
if let Some(idx) = text.find(mark) {
|
||||
text = &text[idx + mark.len()..];
|
||||
if let Some(stripped_text) = text.strip_prefix("!(") {
|
||||
text = stripped_text.trim_start();
|
||||
if let Some(idx2) = text.find(|c: char| !(c.is_alphanumeric() || c == '_')) {
|
||||
let mark_text = &text[..idx2];
|
||||
set.insert(mark_text.to_string());
|
||||
text = &text[idx2..];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user