diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index cba5eb0c688..e19edb21252 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -74,6 +74,12 @@ impl Completions { items.into_iter().for_each(|item| self.add(item.into())) } + pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext, keyword: &'static str) { + let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), keyword); + item.kind(CompletionItemKind::Keyword); + item.add_to(self); + } + pub(crate) fn add_resolution( &mut self, ctx: &CompletionContext, diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 407f796efe4..aabc096e6c4 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -1,7 +1,5 @@ //! Completes keywords. -use std::iter; - use syntax::{SyntaxKind, T}; use crate::{ @@ -9,36 +7,6 @@ use crate::{ CompletionItemKind, CompletionKind, Completions, }; -pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { - // complete keyword "crate" in use stmt - let source_range = ctx.source_range(); - let kw_completion = move |text: &str| { - let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, text); - item.kind(CompletionItemKind::Keyword).insert_text(text); - item - }; - - if ctx.in_use_tree() { - match &ctx.path_context { - Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => { - if iter::successors(Some(qual.clone()), |p| p.qualifier()) - .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) - { - kw_completion("super::").add_to(acc); - } - if *use_tree_parent { - kw_completion("self").add_to(acc); - } - } - _ => { - kw_completion("crate::").add_to(acc); - kw_completion("self::").add_to(acc); - kw_completion("super::").add_to(acc); - } - }; - } -} - pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { if ctx.token.kind() == SyntaxKind::COMMENT { cov_mark::hit!(no_keyword_completion_in_comments); @@ -243,6 +211,9 @@ mod tests { kw for kw let kw return + kw self + kw super + kw crate "#]], ); } @@ -271,6 +242,9 @@ mod tests { kw for kw let kw return + kw self + kw super + kw crate "#]], ); } @@ -301,6 +275,9 @@ mod tests { kw else kw else if kw return + kw self + kw super + kw crate "#]], ); check_edit( @@ -330,6 +307,9 @@ fn quux() -> i32 { kw if let kw for kw return + kw self + kw super + kw crate "#]], ); } @@ -360,6 +340,9 @@ fn quux() -> i32 { kw continue kw break kw return + kw self + kw super + kw crate "#]], ); } @@ -448,6 +431,9 @@ fn foo() { kw if let kw for kw return + kw self + kw super + kw crate "#]], ) } @@ -493,6 +479,9 @@ fn foo() { kw if let kw for kw return + kw self + kw super + kw crate "#]], ); } diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 4875ed65a01..ed0f902017a 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -1,18 +1,22 @@ //! Completion of paths, i.e. `some::prefix::$0`. +use std::iter; + use hir::HasVisibility; use rustc_hash::FxHashSet; -use syntax::AstNode; +use syntax::{ast, AstNode}; -use crate::{CompletionContext, Completions}; +use crate::{context::PathCompletionContext, CompletionContext, Completions}; pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { if ctx.is_path_disallowed() { return; } - let path = match ctx.path_qual() { - Some(path) => path, - None => return, + let (path, use_tree_parent) = match &ctx.path_context { + Some(PathCompletionContext { qualifier: Some(qualifier), use_tree_parent, .. }) => { + (qualifier, *use_tree_parent) + } + _ => return, }; let resolution = match ctx.sema.resolve_path(path) { @@ -39,6 +43,23 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon return; } + if ctx.in_use_tree() { + if iter::successors(Some(path.clone()), |p| p.qualifier()) + .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) + { + acc.add_keyword(ctx, "super::"); + } + // only show `self` in a new use-tree when the qualifier doesn't end in self + if use_tree_parent + && !matches!( + path.segment().and_then(|it| it.kind()), + Some(ast::PathSegmentKind::SelfKw) + ) + { + acc.add_keyword(ctx, "self"); + } + } + // Add associated types on type parameters and `Self`. resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { acc.add_type_alias(ctx, alias); diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 5abd6ee37f7..3ee50957419 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -10,6 +10,21 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC return; } + if ctx.in_use_tree() { + // only show modules in a fresh UseTree + cov_mark::hit!(only_completes_modules_in_import); + ctx.scope.process_all_names(&mut |name, res| { + if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { + acc.add_resolution(ctx, name, &res); + } + }); + + std::array::IntoIter::new(["self::", "super::", "crate::"]) + .for_each(|kw| acc.add_keyword(ctx, kw)); + return; + } + std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw)); + if ctx.expects_item() || ctx.expects_assoc_item() { // only show macros in {Assoc}ItemList ctx.scope.process_all_names(&mut |name, res| { @@ -25,17 +40,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC return; } - if ctx.in_use_tree() { - // only show modules in a fresh UseTree - cov_mark::hit!(only_completes_modules_in_import); - ctx.scope.process_all_names(&mut |name, res| { - if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { - acc.add_resolution(ctx, name, &res); - } - }); - return; - } - if matches!(&ctx.completion_location, Some(ImmediateLocation::TypeBound)) { ctx.scope.process_all_names(&mut |name, res| { let add_resolution = match res { diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 14d2e5cf165..a9f32a42acf 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -150,7 +150,6 @@ pub fn completions( completions::attribute::complete_attribute(&mut acc, &ctx); completions::fn_param::complete_fn_param(&mut acc, &ctx); completions::keyword::complete_expr_keyword(&mut acc, &ctx); - completions::keyword::complete_use_tree_keyword(&mut acc, &ctx); completions::snippet::complete_expr_snippet(&mut acc, &ctx); completions::snippet::complete_item_snippet(&mut acc, &ctx); completions::qualified_path::complete_qualified_path(&mut acc, &ctx); diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs index 8cd5208cc47..a76881f2097 100644 --- a/crates/ide_completion/src/tests/item_list.rs +++ b/crates/ide_completion/src/tests/item_list.rs @@ -30,6 +30,9 @@ fn in_mod_item_list() { sn tmod (Test module) sn tfn (Test function) sn macro_rules + kw self + kw super + kw crate ma makro!(…) #[macro_export] macro_rules! makro "##]], ) @@ -58,6 +61,9 @@ fn in_source_file_item_list() { sn tmod (Test module) sn tfn (Test function) sn macro_rules + kw self + kw super + kw crate ma makro!(…) #[macro_export] macro_rules! makro md module ma makro!(…) #[macro_export] macro_rules! makro @@ -174,6 +180,9 @@ fn in_impl_assoc_item_list() { kw fn kw const kw type + kw self + kw super + kw crate ma makro!(…) #[macro_export] macro_rules! makro md module ma makro!(…) #[macro_export] macro_rules! makro @@ -205,6 +214,9 @@ fn in_trait_assoc_item_list() { kw fn kw const kw type + kw self + kw super + kw crate md module ma makro!(…) #[macro_export] macro_rules! makro ma makro!(…) #[macro_export] macro_rules! makro diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs index ef2015107e3..7df200b486a 100644 --- a/crates/ide_completion/src/tests/items.rs +++ b/crates/ide_completion/src/tests/items.rs @@ -18,6 +18,9 @@ fn target_type_or_trait_in_impl_block() { impl Tra$0 "#, expect![[r##" + kw self + kw super + kw crate tt Trait en Enum st Record @@ -38,6 +41,9 @@ fn target_type_in_trait_impl_block() { impl Trait for Str$0 "#, expect![[r##" + kw self + kw super + kw crate tt Trait en Enum st Record diff --git a/crates/ide_completion/src/tests/predicate.rs b/crates/ide_completion/src/tests/predicate.rs index 2b8ba86b238..0821e22f28c 100644 --- a/crates/ide_completion/src/tests/predicate.rs +++ b/crates/ide_completion/src/tests/predicate.rs @@ -16,6 +16,9 @@ fn predicate_start() { struct Foo<'lt, T, const C: usize> where $0 {} "#, expect![[r##" + kw self + kw super + kw crate tt Trait en Enum st Record @@ -38,6 +41,9 @@ fn bound_for_type_pred() { struct Foo<'lt, T, const C: usize> where T: $0 {} "#, expect![[r##" + kw self + kw super + kw crate tt Trait md module ma makro!(…) #[macro_export] macro_rules! makro @@ -54,6 +60,9 @@ fn bound_for_lifetime_pred() { struct Foo<'lt, T, const C: usize> where 'lt: $0 {} "#, expect![[r##" + kw self + kw super + kw crate tt Trait md module ma makro!(…) #[macro_export] macro_rules! makro @@ -69,6 +78,9 @@ fn bound_for_for_pred() { struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} "#, expect![[r##" + kw self + kw super + kw crate tt Trait md module ma makro!(…) #[macro_export] macro_rules! makro @@ -84,6 +96,9 @@ fn param_list_for_for_pred() { struct Foo<'lt, T, const C: usize> where for<'a> $0 {} "#, expect![[r##" + kw self + kw super + kw crate tt Trait en Enum st Record @@ -107,6 +122,9 @@ impl Record { } "#, expect![[r##" + kw self + kw super + kw crate sp Self tt Trait en Enum diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs index 1b76c5bd399..40571f45b83 100644 --- a/crates/ide_completion/src/tests/type_pos.rs +++ b/crates/ide_completion/src/tests/type_pos.rs @@ -30,6 +30,9 @@ struct Foo<'lt, T, const C: usize> { } "#, expect![[r#" + kw self + kw super + kw crate sp Self tp T tt Trait @@ -54,6 +57,9 @@ struct Foo<'lt, T, const C: usize>(f$0); expect![[r#" kw pub(crate) kw pub + kw self + kw super + kw crate sp Self tp T tt Trait @@ -76,6 +82,9 @@ fn fn_return_type() { fn x<'lt, T, const C: usize>() -> $0 "#, expect![[r#" + kw self + kw super + kw crate tp T tt Trait en Enum @@ -99,6 +108,9 @@ fn foo<'lt, T, const C: usize>() { } "#, expect![[r#" + kw self + kw super + kw crate tp T tt Trait en Enum @@ -140,6 +152,9 @@ trait Trait2 { fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} "#, expect![[r#" + kw self + kw super + kw crate ta Foo = (as Trait2) type Foo; tp T cp CONST_PARAM diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs index 7ad679f10ea..71c618e6690 100644 --- a/crates/ide_completion/src/tests/use_tree.rs +++ b/crates/ide_completion/src/tests/use_tree.rs @@ -22,11 +22,11 @@ mod foo {} // nothing here "#, expect![[r#" - kw crate:: - kw self:: - kw super:: md foo md other_crate + kw self:: + kw super:: + kw crate:: "#]], ); } @@ -41,7 +41,6 @@ mod foo { pub struct S; } use self::{foo::*, bar$0}; "#, expect![[r#" - kw self st S md foo "#]], @@ -230,10 +229,10 @@ pub mod bar {} pub use $0; "#, expect![[r#" - kw crate:: + md bar kw self:: kw super:: - md bar + kw crate:: "#]], ); } @@ -247,10 +246,10 @@ mod bar {} use {$0}; "#, expect![[r#" - kw crate:: + md bar kw self:: kw super:: - md bar + kw crate:: "#]], ); }