diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 36cee48aed6..f8b1ff73109 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -6,6 +6,7 @@ pub(crate) mod extern_abi; pub(crate) mod flyimport; pub(crate) mod fn_param; pub(crate) mod format_string; +pub(crate) mod item_list; pub(crate) mod keyword; pub(crate) mod lifetime; pub(crate) mod mod_; diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs new file mode 100644 index 00000000000..5ae119c534a --- /dev/null +++ b/crates/ide-completion/src/completions/item_list.rs @@ -0,0 +1,48 @@ +//! Completion of paths and keywords at item list position. + +use crate::{ + completions::module_or_fn_macro, + context::{PathCompletionCtx, PathKind, PathQualifierCtx}, + CompletionContext, Completions, +}; + +pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) { + let _p = profile::span("complete_unqualified_path"); + if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() { + return; + } + + let (&is_absolute_path, qualifier) = match &ctx.path_context { + Some(PathCompletionCtx { + kind: Some(PathKind::Item), is_absolute_path, qualifier, .. + }) => (is_absolute_path, qualifier), + _ => return, + }; + + match qualifier { + Some(PathQualifierCtx { resolution, is_super_chain, .. }) => { + if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = resolution { + for (name, def) in module.scope(ctx.db, Some(ctx.module)) { + if let Some(def) = module_or_fn_macro(ctx.db, def) { + acc.add_resolution(ctx, name, def); + } + } + } + + if *is_super_chain { + acc.add_keyword(ctx, "super::"); + } + } + None if is_absolute_path => { + acc.add_crate_roots(ctx); + } + None => { + ctx.process_all_names(&mut |name, def| { + if let Some(def) = module_or_fn_macro(ctx.db, def) { + acc.add_resolution(ctx, name, def); + } + }); + acc.add_nameref_keywords_with_colon(ctx); + } + } +} diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index 07cfad81d26..93bd3468469 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -40,7 +40,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte if let Some(PathKind::Vis { .. }) = ctx.path_kind() { return; } - if ctx.has_impl_or_trait_prev_sibling() { + if ctx.has_unfinished_impl_or_trait_prev_sibling() { add_keyword("where", "where"); if ctx.has_impl_prev_sibling() { add_keyword("for", "for"); diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 16666eba458..a761eeebb2f 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -196,12 +196,13 @@ fn pattern_path_completion( // qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path None if *is_absolute_path => acc.add_crate_roots(ctx), None => { - cov_mark::hit!(unqualified_path_only_modules_in_import); ctx.process_all_names(&mut |name, res| { - if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { + // FIXME: properly filter here + if let ScopeDef::ModuleDef(_) = res { acc.add_resolution(ctx, name, res); } }); + acc.add_nameref_keywords_with_colon(ctx); } } diff --git a/crates/ide-completion/src/completions/qualified_path.rs b/crates/ide-completion/src/completions/qualified_path.rs index ad92820bca9..d12f8490bd1 100644 --- a/crates/ide-completion/src/completions/qualified_path.rs +++ b/crates/ide-completion/src/completions/qualified_path.rs @@ -5,14 +5,12 @@ use ide_db::FxHashSet; use syntax::ast; use crate::{ - completions::module_or_fn_macro, context::{PathCompletionCtx, PathKind}, - patterns::ImmediateLocation, CompletionContext, Completions, }; pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { - if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() { + if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() { return; } if ctx.pattern_ctx.is_some() { @@ -54,26 +52,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon None => return, }; - match ctx.completion_location { - Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { - if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { - for (name, def) in module.scope(ctx.db, Some(ctx.module)) { - if let Some(def) = module_or_fn_macro(ctx.db, def) { - acc.add_resolution(ctx, name, def); - } - } - } - return; - } - _ => (), - } - match kind { Some( PathKind::Pat | PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use + | PathKind::Item | PathKind::Derive, ) => { return; diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs index c00de6ff50f..a1675b896dd 100644 --- a/crates/ide-completion/src/completions/snippet.rs +++ b/crates/ide-completion/src/completions/snippet.rs @@ -46,7 +46,7 @@ pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte if !(ctx.expects_item() || ctx.has_block_expr_parent()) || ctx.previous_token_is(T![unsafe]) || ctx.path_qual().is_some() - || ctx.has_impl_or_trait_prev_sibling() + || ctx.has_unfinished_impl_or_trait_prev_sibling() { return; } diff --git a/crates/ide-completion/src/completions/trait_impl.rs b/crates/ide-completion/src/completions/trait_impl.rs index 80fbaffd71e..d5272be882a 100644 --- a/crates/ide-completion/src/completions/trait_impl.rs +++ b/crates/ide-completion/src/completions/trait_impl.rs @@ -547,12 +547,7 @@ impl Test for T { type Test = fn $0; } ", - expect![[r#" - sp Self - st T - tt Test - bt u32 - "#]], + expect![[r#""#]], ); } diff --git a/crates/ide-completion/src/completions/unqualified_path.rs b/crates/ide-completion/src/completions/unqualified_path.rs index c4d4c5549e4..5de602e6138 100644 --- a/crates/ide-completion/src/completions/unqualified_path.rs +++ b/crates/ide-completion/src/completions/unqualified_path.rs @@ -4,7 +4,6 @@ use hir::ScopeDef; use syntax::{ast, AstNode}; use crate::{ - completions::module_or_fn_macro, context::{PathCompletionCtx, PathKind}, patterns::ImmediateLocation, CompletionContext, Completions, @@ -12,14 +11,15 @@ use crate::{ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { let _p = profile::span("complete_unqualified_path"); - if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() { + if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() { return; } - match ctx.path_context { + + match &ctx.path_context { Some(PathCompletionCtx { is_absolute_path: false, qualifier: None, - kind: None | Some(PathKind::Expr | PathKind::Type | PathKind::Item), + kind: None | Some(PathKind::Expr | PathKind::Type), .. }) => (), _ => return, @@ -28,15 +28,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC acc.add_nameref_keywords(ctx); match &ctx.completion_location { - Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { - // only show macros in {Assoc}ItemList - ctx.process_all_names(&mut |name, def| { - if let Some(def) = module_or_fn_macro(ctx.db, def) { - acc.add_resolution(ctx, name, def); - } - }); - return; - } Some(ImmediateLocation::TypeBound) => { ctx.process_all_names(&mut |name, res| { let add_resolution = match res { diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index a41d89859a9..6682bc56d18 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -270,13 +270,17 @@ impl<'a> CompletionContext<'a> { || matches!(self.name_ctx, Some(NameContext::RecordField)) } - pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { + /// Whether the cursor is right after a trait or impl header. + /// trait Foo ident$0 + // FIXME: This probably shouldn't exist + pub(crate) fn has_unfinished_impl_or_trait_prev_sibling(&self) -> bool { matches!( self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName) ) } + // FIXME: This probably shouldn't exist pub(crate) fn has_impl_prev_sibling(&self) -> bool { matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType)) } @@ -289,6 +293,7 @@ impl<'a> CompletionContext<'a> { matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) } + // FIXME: This shouldn't exist pub(crate) fn is_path_disallowed(&self) -> bool { self.previous_token_is(T![unsafe]) || matches!( diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 6924ba1db6d..473900397ae 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -155,6 +155,7 @@ pub fn completions( completions::flyimport::import_on_the_fly(&mut acc, &ctx); completions::fn_param::complete_fn_param(&mut acc, &ctx); completions::format_string::format_string(&mut acc, &ctx); + completions::item_list::complete_item_list(&mut acc, &ctx); completions::inferred_type(&mut acc, &ctx); completions::keyword::complete_expr_keyword(&mut acc, &ctx); completions::lifetime::complete_label(&mut acc, &ctx); diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs index 8f2f8a548a4..5d324f0965f 100644 --- a/crates/ide-completion/src/tests/item.rs +++ b/crates/ide-completion/src/tests/item.rs @@ -95,7 +95,7 @@ fn after_struct_name() { ma makro!(…) macro_rules! makro md module kw const - kw crate + kw crate:: kw enum kw extern kw fn @@ -104,10 +104,10 @@ fn after_struct_name() { kw pub kw pub(crate) kw pub(super) - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw type kw union @@ -129,7 +129,7 @@ fn after_fn_name() { ma makro!(…) macro_rules! makro md module kw const - kw crate + kw crate:: kw enum kw extern kw fn @@ -138,10 +138,10 @@ fn after_fn_name() { kw pub kw pub(crate) kw pub(super) - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw type kw union diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index 40d3b90da9d..f3208129364 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs @@ -15,7 +15,7 @@ fn in_mod_item_list() { expect![[r#" ma makro!(…) macro_rules! makro kw const - kw crate + kw crate:: kw enum kw extern kw fn @@ -24,10 +24,10 @@ fn in_mod_item_list() { kw pub kw pub(crate) kw pub(super) - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw type kw union @@ -48,7 +48,7 @@ fn in_source_file_item_list() { ma makro!(…) macro_rules! makro md module kw const - kw crate + kw crate:: kw enum kw extern kw fn @@ -57,10 +57,10 @@ fn in_source_file_item_list() { kw pub kw pub(crate) kw pub(super) - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw type kw union @@ -166,13 +166,13 @@ fn in_impl_assoc_item_list() { ma makro!(…) macro_rules! makro md module kw const - kw crate + kw crate:: kw fn kw pub kw pub(crate) kw pub(super) - kw self - kw super + kw self:: + kw super:: kw type kw unsafe "#]], @@ -203,10 +203,10 @@ fn in_trait_assoc_item_list() { ma makro!(…) macro_rules! makro md module kw const - kw crate + kw crate:: kw fn - kw self - kw super + kw self:: + kw super:: kw type kw unsafe "#]], @@ -240,13 +240,13 @@ impl Test for () { md module ta type Type1 = kw const - kw crate + kw crate:: kw fn kw pub kw pub(crate) kw pub(super) - kw self - kw super + kw self:: + kw super:: kw type kw unsafe "#]], diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs index b353883bc7e..3ecb2f16374 100644 --- a/crates/ide-completion/src/tests/pattern.rs +++ b/crates/ide-completion/src/tests/pattern.rs @@ -394,6 +394,9 @@ fn foo() { } "#, expect![[r#" + fn foo() fn() + st Bar + bt u32 kw crate:: kw self:: kw super:: @@ -403,19 +406,18 @@ fn foo() { r#" struct Foo { bar: u32 } fn foo() { - match Foo { bar: 0 } { + match (Foo { bar: 0 }) { F$0 { bar } => {} } } "#, expect![[r#" - fn foo() fn() + fn foo() fn() st Foo bt u32 - kw crate - kw return - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); check_empty(