From 354ad29493dbb258c11190abd7632af95c538e16 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 15:08:44 +0200 Subject: Filter out non-type completions in the respective completions modules instead --- crates/hir/src/lib.rs | 12 --- crates/ide_completion/src/completions.rs | 3 - .../src/completions/qualified_path.rs | 85 +++++++++++++++------- .../src/completions/unqualified_path.rs | 58 ++++++++------- crates/ide_completion/src/context.rs | 4 + crates/ide_completion/src/render.rs | 3 - 6 files changed, 94 insertions(+), 71 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5bc0b2338..b7eabaabb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -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 for ScopeDef { diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index bd90cefb2..aef70f26a 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -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)); } diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 6083537b7..1643eeed4 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -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,10 +175,22 @@ 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)] @@ -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); + +fn foo(_: Foo) {} +"#, + expect![[r#" + ta Type + ct CONST + "#]], + ); + } } diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index f86b2d3f3..b5af1c810 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -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#" -trait Foo { - type Bar; +enum Bar { + Baz } - -fn foo(_: impl Foo) {} -"#, - 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) {} +const CONST: () = (); + +fn foo, const CONST_PARAM: usize>(_: T) {} "#, expect![[r#" - ta Bar = type Bar; + ta Bar = type Bar; tp T + cp CONST_PARAM tt Foo + en Bar + ct CONST "#]], ); } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 4c3929a26..a8437d81c 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -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)) } diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d8ca18c73..add296124 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -55,9 +55,6 @@ pub(crate) fn render_resolution_with_import( import_edit: ImportEdit, ) -> Option { 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)?, -- cgit v1.2.3