Filter out non-type completions in the respective completions modules instead

This commit is contained in:
Lukas Wirth 2021-06-16 15:08:44 +02:00
parent 79703efc7f
commit 354ad29493
6 changed files with 95 additions and 72 deletions

View File

@ -2688,18 +2688,6 @@ impl ScopeDef {
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 {

View File

@ -109,9 +109,6 @@ impl Completions {
local_name: hir::Name,
resolution: &hir::ScopeDef,
) {
if ctx.expects_type() && resolution.is_value_def() {
return;
}
self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
}

View File

@ -19,6 +19,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
Some(res) => res,
None => return,
};
let context_module = ctx.scope.module();
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 {
if !macro_def.is_fn_like() {
// Don't suggest attribute macros and derives.
continue;
let add_resolution = match def {
// Don't suggest attribute macros and derives.
hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
// 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::TypeAlias(_))
| hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => {
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 {
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);
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
cov_mark::hit!(completes_variant_through_alias);
add_enum_variants(ctx, acc, e);
add_enum_variants(acc, ctx, e);
}
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)) {
return None;
}
match 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),
}
add_assoc_item(acc, ctx, item);
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)) {
continue;
}
match 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),
}
add_assoc_item(acc, ctx, item);
}
}
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() {
add_enum_variants(ctx, acc, e);
add_enum_variants(acc, ctx, e);
}
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
// them.
if seen.insert(item) {
match 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),
}
add_assoc_item(acc, ctx, item);
}
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) {
for variant in e.variants(ctx.db) {
acc.add_enum_variant(ctx, variant, None);
fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
match item {
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)]
mod tests {
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
"#]],
);
}
}

View File

@ -36,12 +36,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return;
}
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)
});
if !ctx.expects_type() {
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)
});
}
}
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| {
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) =
res
{
cov_mark::hit!(skip_lifetime_completion);
return;
}
let add_resolution = match res {
// Don't suggest attribute macros and derives.
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,
};
if add_resolution {
@ -794,36 +809,27 @@ $0
}
#[test]
fn completes_assoc_types_in_dynimpl_trait() {
fn completes_types_and_const_in_arg_list() {
check(
r#"
enum Bar {
Baz
}
trait Foo {
type Bar;
}
fn foo(_: impl Foo<B$0>) {}
const CONST: () = ();
fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {}
"#,
expect![[r#"
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;
ta Bar = type Bar;
tp T
cp CONST_PARAM
tt Foo
en Bar
ct CONST
"#]],
);
}

View File

@ -276,6 +276,10 @@ impl<'a> CompletionContext<'a> {
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 {
matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
}

View File

@ -55,9 +55,6 @@ pub(crate) fn render_resolution_with_import(
import_edit: ImportEdit,
) -> Option<CompletionItem> {
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 {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,