diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 9c65efdb1022..c11a1efce4f4 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -2,6 +2,7 @@ pub(crate) mod attribute; pub(crate) mod dot; +pub(crate) mod extern_abi; pub(crate) mod flyimport; pub(crate) mod fn_param; pub(crate) mod format_string; diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 4a34b0f7e562..3bb3f883cdb9 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -684,12 +684,12 @@ struct Foo { field: i32 } impl Foo { fn foo(&self) { $0 } }"#, expect![[r#" + fd self.field i32 + me self.foo() fn(&self) lc self &Foo sp Self st Foo bt u32 - fd self.field i32 - me self.foo() fn(&self) "#]], ); check( @@ -698,12 +698,12 @@ struct Foo(i32); impl Foo { fn foo(&mut self) { $0 } }"#, expect![[r#" + fd self.0 i32 + me self.foo() fn(&mut self) lc self &mut Foo sp Self st Foo bt u32 - fd self.0 i32 - me self.foo() fn(&mut self) "#]], ); } diff --git a/crates/ide_completion/src/completions/extern_abi.rs b/crates/ide_completion/src/completions/extern_abi.rs new file mode 100644 index 000000000000..87fccec008e0 --- /dev/null +++ b/crates/ide_completion/src/completions/extern_abi.rs @@ -0,0 +1,104 @@ +//! Completes function abi strings. +use syntax::{ + ast::{self, IsString}, + AstNode, AstToken, +}; + +use crate::{ + completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind, +}; + +// Most of these are feature gated, we should filter/add feature gate completions once we have them. +const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ + "Rust", + "C", + "C-unwind", + "cdecl", + "stdcall", + "stdcall-unwind", + "fastcall", + "vectorcall", + "thiscall", + "thiscall-unwind", + "aapcs", + "win64", + "sysv64", + "ptx-kernel", + "msp430-interrupt", + "x86-interrupt", + "amdgpu-kernel", + "efiapi", + "avr-interrupt", + "avr-non-blocking-interrupt", + "C-cmse-nonsecure-call", + "wasm", + "system", + "system-unwind", + "rust-intrinsic", + "rust-call", + "platform-intrinsic", + "unadjusted", +]; + +pub(crate) fn complete_extern_abi(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { + if ctx.token.parent().and_then(ast::Abi::cast).is_none() { + return None; + } + let abi_str = ast::String::cast(ctx.token.clone())?; + let source_range = abi_str.text_range_between_quotes()?; + for &abi in SUPPORTED_CALLING_CONVENTIONS { + CompletionItem::new(CompletionItemKind::Keyword, source_range, abi).add_to(acc); + } + Some(()) +} + +#[cfg(test)] +mod tests { + use expect_test::{expect, Expect}; + + use crate::tests::{check_edit, completion_list_no_kw}; + + fn check(ra_fixture: &str, expect: Expect) { + let actual = completion_list_no_kw(ra_fixture); + expect.assert_eq(&actual); + } + + #[test] + fn only_completes_in_string_literals() { + check( + r#" +$0 fn foo {} +"#, + expect![[]], + ); + } + + #[test] + fn requires_extern_prefix() { + check( + r#" +"$0" fn foo {} +"#, + expect![[]], + ); + } + + #[test] + fn works() { + check( + r#" +extern "$0" fn foo {} +"#, + expect![[]], + ); + check_edit( + "Rust", + r#" +extern "$0" fn foo {} +"#, + r#" +extern "Rust" fn foo {} +"#, + ); + } +} diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index f0cd125973a2..9f6f6592de50 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -151,27 +151,28 @@ pub fn completions( } let mut acc = Completions::default(); - completions::attribute::complete_known_attribute_input(&mut acc, &ctx); completions::attribute::complete_attribute(&mut acc, &ctx); - completions::use_::complete_use_tree(&mut acc, &ctx); - completions::vis::complete_vis(&mut acc, &ctx); - completions::fn_param::complete_fn_param(&mut acc, &ctx); - completions::keyword::complete_expr_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); - completions::unqualified_path::complete_unqualified_path(&mut acc, &ctx); + completions::attribute::complete_known_attribute_input(&mut acc, &ctx); completions::dot::complete_dot(&mut acc, &ctx); - completions::record::complete_record(&mut acc, &ctx); - completions::record::complete_record_literal(&mut acc, &ctx); + completions::extern_abi::complete_extern_abi(&mut acc, &ctx); + 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::keyword::complete_expr_keyword(&mut acc, &ctx); + completions::lifetime::complete_label(&mut acc, &ctx); + completions::lifetime::complete_lifetime(&mut acc, &ctx); + completions::mod_::complete_mod(&mut acc, &ctx); completions::pattern::complete_pattern(&mut acc, &ctx); completions::postfix::complete_postfix(&mut acc, &ctx); + completions::qualified_path::complete_qualified_path(&mut acc, &ctx); + completions::record::complete_record_literal(&mut acc, &ctx); + completions::record::complete_record(&mut acc, &ctx); + completions::snippet::complete_expr_snippet(&mut acc, &ctx); + completions::snippet::complete_item_snippet(&mut acc, &ctx); completions::trait_impl::complete_trait_impl(&mut acc, &ctx); - completions::mod_::complete_mod(&mut acc, &ctx); - completions::flyimport::import_on_the_fly(&mut acc, &ctx); - completions::lifetime::complete_lifetime(&mut acc, &ctx); - completions::lifetime::complete_label(&mut acc, &ctx); - completions::format_string::format_string(&mut acc, &ctx); + completions::unqualified_path::complete_unqualified_path(&mut acc, &ctx); + completions::use_::complete_use_tree(&mut acc, &ctx); + completions::vis::complete_vis(&mut acc, &ctx); Some(acc) } diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs index 56a2cd6e9dcc..5e1fae68fd2a 100644 --- a/crates/ide_completion/src/tests/expression.rs +++ b/crates/ide_completion/src/tests/expression.rs @@ -126,6 +126,7 @@ impl Unit { "#, // `self` is in here twice, once as the module, once as the local expect![[r##" + me self.foo() fn(self) kw unsafe kw fn kw const @@ -172,7 +173,6 @@ impl Unit { un Union ev TupleV(…) (u32) ct CONST - me self.foo() fn(self) "##]], ); check( diff --git a/crates/ide_completion/src/tests/record.rs b/crates/ide_completion/src/tests/record.rs index e09e99aad5e7..3bb332b43725 100644 --- a/crates/ide_completion/src/tests/record.rs +++ b/crates/ide_completion/src/tests/record.rs @@ -166,6 +166,10 @@ fn main() { kw true kw false kw return + sn Foo {…} Foo { foo1: ${1:()}, foo2: ${2:()} }$0 + fd ..Default::default() + fd foo1 u32 + fd foo2 u32 kw self kw super kw crate @@ -177,10 +181,6 @@ fn main() { bt u32 tt Sized tt Default - fd ..Default::default() - fd foo1 u32 - fd foo2 u32 - sn Foo {…} Foo { foo1: ${1:()}, foo2: ${2:()} }$0 "#]], ); check(