mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Merge #9299
9299: minor: Filter out non-type completions in the respective completions modules instead r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
1c034c084d
6 changed files with 95 additions and 72 deletions
|
@ -2688,18 +2688,6 @@ impl ScopeDef {
|
||||||
|
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_value_def(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
ScopeDef::ModuleDef(ModuleDef::Function(_))
|
|
||||||
| ScopeDef::ModuleDef(ModuleDef::Variant(_))
|
|
||||||
| ScopeDef::ModuleDef(ModuleDef::Const(_))
|
|
||||||
| ScopeDef::ModuleDef(ModuleDef::Static(_))
|
|
||||||
| ScopeDef::GenericParam(GenericParam::ConstParam(_))
|
|
||||||
| ScopeDef::Local(_)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ItemInNs> for ScopeDef {
|
impl From<ItemInNs> for ScopeDef {
|
||||||
|
|
|
@ -109,9 +109,6 @@ impl Completions {
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
resolution: &hir::ScopeDef,
|
resolution: &hir::ScopeDef,
|
||||||
) {
|
) {
|
||||||
if ctx.expects_type() && resolution.is_value_def() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
|
self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let context_module = ctx.scope.module();
|
let context_module = ctx.scope.module();
|
||||||
|
|
||||||
if ctx.expects_item() || ctx.expects_assoc_item() {
|
if ctx.expects_item() || ctx.expects_assoc_item() {
|
||||||
|
@ -60,21 +61,31 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let hir::ScopeDef::MacroDef(macro_def) = def {
|
let add_resolution = match def {
|
||||||
if !macro_def.is_fn_like() {
|
// Don't suggest attribute macros and derives.
|
||||||
// Don't suggest attribute macros and derives.
|
hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
||||||
continue;
|
// no values in type places
|
||||||
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(_))
|
||||||
|
| hir::ScopeDef::ModuleDef(hir::ModuleDef::Variant(_))
|
||||||
|
| hir::ScopeDef::ModuleDef(hir::ModuleDef::Static(_))
|
||||||
|
| hir::ScopeDef::Local(_) => !ctx.expects_type(),
|
||||||
|
// unless its a constant in a generic arg list position
|
||||||
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
|
||||||
|
!ctx.expects_type() || ctx.expects_generic_arg()
|
||||||
}
|
}
|
||||||
}
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
acc.add_resolution(ctx, name, &def);
|
if add_resolution {
|
||||||
|
acc.add_resolution(ctx, name, &def);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_))
|
hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_))
|
||||||
| hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_))
|
| hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_))
|
||||||
| hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => {
|
| hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => {
|
||||||
if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
||||||
add_enum_variants(ctx, acc, e);
|
add_enum_variants(acc, ctx, e);
|
||||||
}
|
}
|
||||||
let ty = match def {
|
let ty = match def {
|
||||||
hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
|
hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
|
||||||
|
@ -82,7 +93,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
let ty = a.ty(ctx.db);
|
let ty = a.ty(ctx.db);
|
||||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
cov_mark::hit!(completes_variant_through_alias);
|
cov_mark::hit!(completes_variant_through_alias);
|
||||||
add_enum_variants(ctx, acc, e);
|
add_enum_variants(acc, ctx, e);
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -107,11 +118,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match item {
|
add_assoc_item(acc, ctx, item);
|
||||||
hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
|
|
||||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
|
||||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
|
||||||
}
|
|
||||||
None::<()>
|
None::<()>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -133,11 +140,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match item {
|
add_assoc_item(acc, ctx, item);
|
||||||
hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
|
|
||||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
|
||||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
||||||
|
@ -149,7 +152,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
add_enum_variants(ctx, acc, e);
|
add_enum_variants(acc, ctx, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let traits_in_scope = ctx.scope.traits_in_scope();
|
let traits_in_scope = ctx.scope.traits_in_scope();
|
||||||
|
@ -162,11 +165,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
// We might iterate candidates of a trait multiple times here, so deduplicate
|
// We might iterate candidates of a trait multiple times here, so deduplicate
|
||||||
// them.
|
// them.
|
||||||
if seen.insert(item) {
|
if seen.insert(item) {
|
||||||
match item {
|
add_assoc_item(acc, ctx, item);
|
||||||
hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
|
|
||||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
|
||||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None::<()>
|
None::<()>
|
||||||
});
|
});
|
||||||
|
@ -176,12 +175,24 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) {
|
fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
|
||||||
for variant in e.variants(ctx.db) {
|
match item {
|
||||||
acc.add_enum_variant(ctx, variant, None);
|
hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
|
||||||
|
hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
|
||||||
|
acc.add_const(ctx, ct)
|
||||||
|
}
|
||||||
|
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
|
||||||
|
if ctx.expects_type() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
@ -927,4 +938,24 @@ fn main() {
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_types_and_const_in_arg_list() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub const CONST: () = ();
|
||||||
|
pub type Type = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo<T>(t);
|
||||||
|
|
||||||
|
fn foo(_: Foo<foo::$0>) {}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
ta Type
|
||||||
|
ct CONST
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hir::Adt::Enum(e)) =
|
if !ctx.expects_type() {
|
||||||
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
|
if let Some(hir::Adt::Enum(e)) =
|
||||||
{
|
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
|
||||||
super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| {
|
{
|
||||||
acc.add_qualified_enum_variant(ctx, variant, path)
|
super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| {
|
||||||
});
|
acc.add_qualified_enum_variant(ctx, variant, path)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
|
if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
|
||||||
|
@ -59,12 +61,25 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.scope.process_all_names(&mut |name, res| {
|
ctx.scope.process_all_names(&mut |name, res| {
|
||||||
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
|
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) =
|
||||||
|
res
|
||||||
|
{
|
||||||
cov_mark::hit!(skip_lifetime_completion);
|
cov_mark::hit!(skip_lifetime_completion);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let add_resolution = match res {
|
let add_resolution = match res {
|
||||||
|
// Don't suggest attribute macros and derives.
|
||||||
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
||||||
|
// no values in type places
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Function(_))
|
||||||
|
| ScopeDef::ModuleDef(hir::ModuleDef::Variant(_))
|
||||||
|
| ScopeDef::ModuleDef(hir::ModuleDef::Static(_))
|
||||||
|
| ScopeDef::Local(_) => !ctx.expects_type(),
|
||||||
|
// unless its a constant in a generic arg list position
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Const(_))
|
||||||
|
| ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => {
|
||||||
|
!ctx.expects_type() || ctx.expects_generic_arg()
|
||||||
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
if add_resolution {
|
if add_resolution {
|
||||||
|
@ -794,36 +809,27 @@ $0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_assoc_types_in_dynimpl_trait() {
|
fn completes_types_and_const_in_arg_list() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
|
enum Bar {
|
||||||
|
Baz
|
||||||
|
}
|
||||||
trait Foo {
|
trait Foo {
|
||||||
type Bar;
|
type Bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(_: impl Foo<B$0>) {}
|
const CONST: () = ();
|
||||||
|
|
||||||
|
fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ta Bar = type Bar;
|
ta Bar = type Bar;
|
||||||
tt Foo
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_assoc_types_in_trait_bound() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
trait Foo {
|
|
||||||
type Bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foo<T: Foo<B$0>>(_: T) {}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
ta Bar = type Bar;
|
|
||||||
tp T
|
tp T
|
||||||
|
cp CONST_PARAM
|
||||||
tt Foo
|
tt Foo
|
||||||
|
en Bar
|
||||||
|
ct CONST
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,6 +276,10 @@ impl<'a> CompletionContext<'a> {
|
||||||
matches!(self.completion_location, Some(ImmediateLocation::ItemList))
|
matches!(self.completion_location, Some(ImmediateLocation::ItemList))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn expects_generic_arg(&self) -> bool {
|
||||||
|
matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_)))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn has_block_expr_parent(&self) -> bool {
|
pub(crate) fn has_block_expr_parent(&self) -> bool {
|
||||||
matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
|
matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,6 @@ pub(crate) fn render_resolution_with_import(
|
||||||
import_edit: ImportEdit,
|
import_edit: ImportEdit,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let resolution = hir::ScopeDef::from(import_edit.import.original_item);
|
let resolution = hir::ScopeDef::from(import_edit.import.original_item);
|
||||||
if ctx.completion.expects_type() && resolution.is_value_def() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let local_name = match resolution {
|
let local_name = match resolution {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue