Unnamed repository; edit this file 'description' to name the repository.
Fix complete after `extern`, add `crate` completion
Example --- ```rust extern "C" $0 ``` **Before this PR** Can't be completion **After this PR** ```text kw async kw const kw enum kw fn kw impl kw impl for kw mod kw pub kw pub(crate) kw pub(super) kw static kw struct kw trait kw type kw union kw unsafe kw use ``` --- ```rust extern $0 ``` **Before this PR** Can't be completion **After this PR** ```rust extern crate $0; ```
A4-Tacks 5 months ago
parent e7f5604 · commit 8e58663
-rw-r--r--crates/ide-completion/src/completions/item_list.rs10
-rw-r--r--crates/ide-completion/src/context.rs2
-rw-r--r--crates/ide-completion/src/context/analysis.rs1
-rw-r--r--crates/ide-completion/src/tests/item_list.rs99
4 files changed, 110 insertions, 2 deletions
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 6c001bd16b..39048e4400 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -87,6 +87,9 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
let in_block = kind.is_none();
let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
+ let no_abi_qualifiers = ctx.qualifier_ctx.abi_node.is_none();
+ let has_extern_kw =
+ ctx.qualifier_ctx.abi_node.as_ref().is_some_and(|it| it.string_token().is_none());
let has_unsafe_kw = ctx.qualifier_ctx.unsafe_tok.is_some();
let has_async_kw = ctx.qualifier_ctx.async_tok.is_some();
let has_safe_kw = ctx.qualifier_ctx.safe_tok.is_some();
@@ -118,7 +121,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
}
}
- if !has_async_kw && no_vis_qualifiers && in_item_list {
+ if !has_async_kw && no_vis_qualifiers && no_abi_qualifiers && in_item_list {
add_keyword("extern", "extern $0");
}
@@ -159,11 +162,14 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
add_keyword("static", "static $1: $2;");
} else {
if !in_inherent_impl {
- if !in_trait {
+ if !in_trait && no_abi_qualifiers {
add_keyword("extern", "extern $0");
}
add_keyword("type", "type $0");
}
+ if has_extern_kw {
+ add_keyword("crate", "crate $0;");
+ }
add_keyword("fn", "fn $1($2) {\n $0\n}");
add_keyword("unsafe", "unsafe $0");
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 31a9a74aa8..23318e1d19 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -53,6 +53,7 @@ pub(crate) struct QualifierCtx {
pub(crate) unsafe_tok: Option<SyntaxToken>,
pub(crate) safe_tok: Option<SyntaxToken>,
pub(crate) vis_node: Option<ast::Visibility>,
+ pub(crate) abi_node: Option<ast::Abi>,
}
impl QualifierCtx {
@@ -61,6 +62,7 @@ impl QualifierCtx {
&& self.unsafe_tok.is_none()
&& self.safe_tok.is_none()
&& self.vis_node.is_none()
+ && self.abi_node.is_none()
}
}
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index e84c065336..da9464f48a 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1628,6 +1628,7 @@ fn classify_name_ref<'db>(
}
}
qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast);
+ qualifier_ctx.abi_node = error_node.children().find_map(ast::Abi::cast);
}
if let PathKind::Item { .. } = path_ctx.kind
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index ac32649d4f..9afc8b49d6 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -177,6 +177,105 @@ fn after_visibility_unsafe() {
}
#[test]
+fn after_abi() {
+ check_with_base_items(
+ r#"extern "C" $0"#,
+ expect![[r#"
+ kw async
+ kw const
+ kw enum
+ kw fn
+ kw impl
+ kw impl for
+ kw mod
+ kw pub
+ kw pub(crate)
+ kw pub(super)
+ kw static
+ kw struct
+ kw trait
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ "#]],
+ );
+ check_with_base_items(
+ r#"extern "C" f$0"#,
+ expect![[r#"
+ kw async
+ kw const
+ kw enum
+ kw fn
+ kw impl
+ kw impl for
+ kw mod
+ kw pub
+ kw pub(crate)
+ kw pub(super)
+ kw static
+ kw struct
+ kw trait
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ "#]],
+ );
+}
+
+#[test]
+fn after_extern_token() {
+ check_with_base_items(
+ r#"extern $0"#,
+ expect![[r#"
+ kw async
+ kw const
+ kw crate
+ kw enum
+ kw fn
+ kw impl
+ kw impl for
+ kw mod
+ kw pub
+ kw pub(crate)
+ kw pub(super)
+ kw static
+ kw struct
+ kw trait
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ "#]],
+ );
+ check_with_base_items(
+ r#"extern cr$0"#,
+ expect![[r#"
+ kw async
+ kw const
+ kw crate
+ kw enum
+ kw fn
+ kw impl
+ kw impl for
+ kw mod
+ kw pub
+ kw pub(crate)
+ kw pub(super)
+ kw static
+ kw struct
+ kw trait
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ "#]],
+ );
+ check_edit("crate", "extern $0", "extern crate $0;");
+}
+
+#[test]
fn in_impl_assoc_item_list() {
check_with_base_items(
r#"impl Struct { $0 }"#,