diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 783305005ca..cba5eb0c688 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -41,9 +41,9 @@ pub struct Completions { buf: Vec, } -impl Into> for Completions { - fn into(self) -> Vec { - self.buf +impl From for Vec { + fn from(val: Completions) -> Self { + val.buf } } @@ -74,35 +74,6 @@ impl Completions { items.into_iter().for_each(|item| self.add(item.into())) } - pub(crate) fn add_field( - &mut self, - ctx: &CompletionContext, - receiver: Option, - field: hir::Field, - ty: &hir::Type, - ) { - let item = render_field(RenderContext::new(ctx), receiver, field, ty); - self.add(item); - } - - pub(crate) fn add_tuple_field( - &mut self, - ctx: &CompletionContext, - receiver: Option, - field: usize, - ty: &hir::Type, - ) { - let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); - self.add(item); - } - - pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { - let mut item = - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); - item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); - self.add(item.build()); - } - pub(crate) fn add_resolution( &mut self, ctx: &CompletionContext, @@ -144,33 +115,6 @@ impl Completions { self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); } - pub(crate) fn add_variant_pat( - &mut self, - ctx: &CompletionContext, - variant: hir::Variant, - local_name: Option, - ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); - } - - pub(crate) fn add_qualified_variant_pat( - &mut self, - ctx: &CompletionContext, - variant: hir::Variant, - path: hir::ModPath, - ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); - } - - pub(crate) fn add_struct_pat( - &mut self, - ctx: &CompletionContext, - strukt: hir::Struct, - local_name: Option, - ) { - self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); - } - pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { self.add_opt(render_const(RenderContext::new(ctx), constant)); } @@ -206,10 +150,67 @@ impl Completions { let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); self.add(item); } + + pub(crate) fn add_field( + &mut self, + ctx: &CompletionContext, + receiver: Option, + field: hir::Field, + ty: &hir::Type, + ) { + let item = render_field(RenderContext::new(ctx), receiver, field, ty); + self.add(item); + } + + pub(crate) fn add_tuple_field( + &mut self, + ctx: &CompletionContext, + receiver: Option, + field: usize, + ty: &hir::Type, + ) { + let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); + self.add(item); + } + + pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { + let mut item = + CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); + item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); + self.add(item.build()); + } + + pub(crate) fn add_variant_pat( + &mut self, + ctx: &CompletionContext, + variant: hir::Variant, + local_name: Option, + ) { + self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); + } + + pub(crate) fn add_qualified_variant_pat( + &mut self, + ctx: &CompletionContext, + variant: hir::Variant, + path: hir::ModPath, + ) { + self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); + } + + pub(crate) fn add_struct_pat( + &mut self, + ctx: &CompletionContext, + strukt: hir::Struct, + local_name: Option, + ) { + self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); + } } /// Calls the callback for each variant of the provided enum with the path to the variant. -fn complete_enum_variants( +/// Skips variants that are visible with single segment paths. +fn enum_variants_with_paths( acc: &mut Completions, ctx: &CompletionContext, enum_: hir::Enum, diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 6df569c2a21..3866c5917d6 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -322,7 +322,7 @@ mod tests { use expect_test::{expect, Expect}; - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; #[test] fn attributes_are_sorted() { @@ -341,7 +341,7 @@ mod tests { } fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Attribute); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Attribute); expect.assert_eq(&actual); } diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 20bbbba4643..5201095e80c 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs @@ -82,7 +82,7 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ mod tests { use expect_test::{expect, Expect}; - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; fn check(ra_fixture: &str, expect: Expect) { let builtin_derives = r#" @@ -106,7 +106,7 @@ pub macro PartialOrd {} pub macro Ord {} "#; - let actual = completion_list( + let actual = filtered_completion_list( &format!("{} {}", builtin_derives, ra_fixture), CompletionKind::Attribute, ); diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index ca99e975926..4812b075cdf 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs @@ -34,7 +34,7 @@ pub(super) fn complete_lint( #[cfg(test)] mod tests { - use crate::test_utils::check_edit; + use crate::tests::check_edit; #[test] fn check_empty() { diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 9552875c11f..7f75d42988c 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -101,10 +101,10 @@ fn complete_methods( mod tests { use expect_test::{expect, Expect}; - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Reference); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual); } diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 30b8d44bd84..4604feb5dc7 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs @@ -227,11 +227,11 @@ mod tests { use crate::{ item::CompletionKind, - test_utils::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, + tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG}, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Magic); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); expect.assert_eq(&actual); } diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index cb90e8a3e11..c9f0e2473af 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs @@ -64,10 +64,10 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) mod tests { use expect_test::{expect, Expect}; - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Magic); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); expect.assert_eq(&actual); } diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0fccbeccfd7..73bbc43458e 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -75,7 +75,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte return; } - if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { + if !ctx.has_visibility_prev_sibling() + && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field()) + { add_keyword("pub(crate)", "pub(crate) "); add_keyword("pub", "pub "); } @@ -88,11 +90,13 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte } if expects_item || has_block_expr_parent { + if !ctx.has_visibility_prev_sibling() { + add_keyword("impl", "impl $1 {\n $0\n}"); + add_keyword("extern", "extern $0"); + } add_keyword("use", "use $0"); - add_keyword("impl", "impl $1 {\n $0\n}"); add_keyword("trait", "trait $1 {\n $0\n}"); add_keyword("static", "static $0"); - add_keyword("extern", "extern $0"); add_keyword("mod", "mod $0"); } @@ -186,12 +190,12 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list}, + tests::{check_edit, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Keyword); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword); expect.assert_eq(&actual) } @@ -230,30 +234,6 @@ mod tests { ); } - #[test] - fn test_keywords_at_source_file_level() { - check( - r"m$0", - expect![[r#" - kw pub(crate) - kw pub - kw unsafe - kw fn - kw const - kw type - kw use - kw impl - kw trait - kw static - kw extern - kw mod - kw enum - kw struct - kw union - "#]], - ); - } - #[test] fn test_keywords_in_function() { check( @@ -263,11 +243,11 @@ mod tests { kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw match kw while @@ -291,11 +271,11 @@ mod tests { kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw match kw while @@ -319,11 +299,11 @@ mod tests { kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw match kw while @@ -369,49 +349,6 @@ fn quux() -> i32 { ); } - #[test] - fn test_keywords_in_trait_def() { - check( - r"trait My { $0 }", - expect![[r#" - kw unsafe - kw fn - kw const - kw type - "#]], - ); - } - - #[test] - fn test_keywords_in_impl_def() { - check( - r"impl My { $0 }", - expect![[r#" - kw pub(crate) - kw pub - kw unsafe - kw fn - kw const - kw type - "#]], - ); - } - - #[test] - fn test_keywords_in_impl_def_with_attr() { - check( - r"impl My { #[foo] $0 }", - expect![[r#" - kw pub(crate) - kw pub - kw unsafe - kw fn - kw const - kw type - "#]], - ); - } - #[test] fn test_keywords_in_loop() { check( @@ -421,11 +358,11 @@ fn quux() -> i32 { kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw match kw while @@ -442,18 +379,6 @@ fn quux() -> i32 { ); } - #[test] - fn test_keywords_after_unsafe_in_item_list() { - check( - r"unsafe $0", - expect![[r#" - kw fn - kw trait - kw impl - "#]], - ); - } - #[test] fn test_keywords_after_unsafe_in_block_expr() { check( diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 8ccccb64606..36f59516468 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs @@ -50,7 +50,7 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, + tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG}, CompletionConfig, CompletionKind, }; @@ -59,7 +59,8 @@ mod tests { } fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { - let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); + let actual = + filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual) } diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs index 6a5746fb94f..5def0d06adc 100644 --- a/crates/ide_completion/src/completions/mod_.rs +++ b/crates/ide_completion/src/completions/mod_.rs @@ -141,11 +141,11 @@ fn module_chain_to_containing_module_file( #[cfg(test)] mod tests { - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; use expect_test::{expect, Expect}; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Magic); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); expect.assert_eq(&actual); } diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 1daa8595a6a..efe3c957ae7 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs @@ -13,7 +13,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 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| { + super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { acc.add_qualified_variant_pat(ctx, variant, path.clone()); acc.add_qualified_enum_variant(ctx, variant, path); }); @@ -61,17 +61,17 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list}, + tests::{check_edit, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Reference); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual) } fn check_snippet(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Snippet); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); expect.assert_eq(&actual) } diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 9f98b21be22..c3c7e4589c8 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs @@ -307,12 +307,12 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list}, + tests::{check_edit, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Postfix); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix); expect.assert_eq(&actual) } diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 1643eeed408..9432caa22e4 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -198,17 +198,17 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list}, + tests::{check_edit, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Reference); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual); } fn check_builtin(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); + let actual = filtered_completion_list(ra_fixture, CompletionKind::BuiltinType); expect.assert_eq(&actual); } @@ -713,24 +713,6 @@ impl MyStruct { ); } - #[test] - fn completes_in_item_list() { - check( - r#" -struct MyStruct {} -#[macro_export] -macro_rules! foo {} -mod bar {} - -crate::$0 -"#, - expect![[r#" - md bar - ma foo!(…) #[macro_export] macro_rules! foo - "#]], - ) - } - #[test] fn test_super_super_completion() { check( diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 0ac47cdbe7e..47523f72f1d 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs @@ -51,17 +51,17 @@ mod tests { use ide_db::helpers::FamousDefs; use crate::{ - test_utils::{self, completion_list}, + tests::{self, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Reference); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual); } fn check_snippet(ra_fixture: &str, expect: Expect) { - let actual = completion_list( + let actual = filtered_completion_list( &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE), CompletionKind::Snippet, ); @@ -69,7 +69,7 @@ mod tests { } fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - test_utils::check_edit( + tests::check_edit( what, &format!( "//- /main.rs crate:main deps:core{}\n{}", diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index b9862de677f..81ddfa34fdc 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -1,6 +1,7 @@ //! This file provides snippet completions, like `pd` => `eprintln!(...)`. use ide_db::helpers::SnippetCap; +use syntax::T; use crate::{ context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, @@ -35,9 +36,13 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte } pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.expects_item() { + if !ctx.expects_item() || ctx.previous_token_is(T![unsafe]) || ctx.path_qual().is_some() { return; } + if ctx.has_visibility_prev_sibling() { + return; // technically we could do some of these snippet completions if we were to put the + // attributes before the vis node. + } let cap = match ctx.config.snippet_cap { Some(it) => it, None => return, @@ -82,10 +87,10 @@ fn ${1:feature}() { mod tests { use expect_test::{expect, Expect}; - use crate::{test_utils::completion_list, CompletionKind}; + use crate::{tests::filtered_completion_list, CompletionKind}; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Snippet); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); expect.assert_eq(&actual) } @@ -105,21 +110,4 @@ mod tests { check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); } - - #[test] - fn completes_snippets_in_items() { - check( - r#" -#[cfg(test)] -mod tests { - $0 -} -"#, - expect![[r#" - sn tmod (Test module) - sn tfn (Test function) - sn macro_rules - "#]], - ) - } } diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a60e5f43c1c..dc1d198cc23 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs @@ -246,12 +246,12 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list}, + tests::{check_edit, filtered_completion_list}, CompletionKind, }; fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture, CompletionKind::Magic); + let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); expect.assert_eq(&actual) } diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index b5af1c81030..2868d9b1813 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -40,7 +40,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC 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| { + super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { acc.add_qualified_enum_variant(ctx, variant, path) }); } @@ -93,7 +93,7 @@ mod tests { use expect_test::{expect, Expect}; use crate::{ - test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, + tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG}, CompletionConfig, CompletionKind, }; @@ -102,7 +102,8 @@ mod tests { } fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { - let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); + let actual = + filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference); expect.assert_eq(&actual) } @@ -500,18 +501,6 @@ fn f() {$0} check( r#" #[rustc_builtin_macro] -pub macro Clone {} - -struct S; -impl S { - $0 -} -"#, - expect![[r#""#]], - ); - check( - r#" -#[rustc_builtin_macro] pub macro bench {} fn f() {$0} @@ -772,42 +761,6 @@ impl My$0 ) } - #[test] - fn completes_in_assoc_item_list() { - check( - r#" -macro_rules! foo {} -mod bar {} - -struct MyStruct {} -impl MyStruct { - $0 -} -"#, - expect![[r#" - md bar - ma foo!(…) macro_rules! foo - "#]], - ) - } - - #[test] - fn completes_in_item_list() { - check( - r#" -struct MyStruct {} -macro_rules! foo {} -mod bar {} - -$0 -"#, - expect![[r#" - md bar - ma foo!(…) macro_rules! foo - "#]], - ) - } - #[test] fn completes_types_and_const_in_arg_list() { check( diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index a8437d81c73..121909857bd 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -302,18 +302,28 @@ impl<'a> CompletionContext<'a> { ) } + pub(crate) fn has_visibility_prev_sibling(&self) -> bool { + matches!(self.prev_sibling, Some(ImmediatePrevSibling::Visibility)) + } + pub(crate) fn after_if(&self) -> bool { matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) } pub(crate) fn is_path_disallowed(&self) -> bool { - matches!( - self.completion_location, - Some(ImmediateLocation::Attribute(_)) - | Some(ImmediateLocation::ModDeclaration(_)) - | Some(ImmediateLocation::RecordPat(_)) - | Some(ImmediateLocation::RecordExpr(_)) - ) || self.attribute_under_caret.is_some() + self.attribute_under_caret.is_some() + || self.previous_token_is(T![unsafe]) + || matches!( + self.prev_sibling, + Some(ImmediatePrevSibling::Attribute) | Some(ImmediatePrevSibling::Visibility) + ) + || matches!( + self.completion_location, + Some(ImmediateLocation::Attribute(_)) + | Some(ImmediateLocation::ModDeclaration(_)) + | Some(ImmediateLocation::RecordPat(_)) + | Some(ImmediateLocation::RecordExpr(_)) + ) } pub(crate) fn expects_expression(&self) -> bool { @@ -685,7 +695,7 @@ mod tests { use expect_test::{expect, Expect}; use hir::HirDisplay; - use crate::test_utils::{position, TEST_CONFIG}; + use crate::tests::{position, TEST_CONFIG}; use super::CompletionContext; diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 18983aa01b1..bf73818dc56 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -1,14 +1,14 @@ //! `completions` crate provides utilities for generating completions of user input. +mod completions; mod config; -mod item; mod context; +mod item; mod patterns; -#[cfg(test)] -mod test_utils; mod render; -mod completions; +#[cfg(test)] +mod tests; use completions::flyimport::position_for_import; use ide_db::{ @@ -141,6 +141,7 @@ pub fn completions( let ctx = CompletionContext::new(db, position, config)?; if ctx.no_completion_required() { + cov_mark::hit!(no_completion_required); // No work required here. return None; } @@ -200,117 +201,3 @@ pub fn resolve_completion_edits( ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) } - -#[cfg(test)] -mod tests { - use crate::test_utils::{self, TEST_CONFIG}; - - struct DetailAndDocumentation<'a> { - detail: &'a str, - documentation: &'a str, - } - - fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) { - let (db, position) = test_utils::position(ra_fixture); - let config = TEST_CONFIG; - let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into(); - for item in completions { - if item.detail() == Some(expected.detail) { - let opt = item.documentation(); - let doc = opt.as_ref().map(|it| it.as_str()); - assert_eq!(doc, Some(expected.documentation)); - return; - } - } - panic!("completion detail not found: {}", expected.detail) - } - - fn check_no_completion(ra_fixture: &str) { - let (db, position) = test_utils::position(ra_fixture); - let config = TEST_CONFIG; - - let completions: Option> = crate::completions(&db, &config, position) - .and_then(|completions| { - let completions: Vec<_> = completions.into(); - if completions.is_empty() { - None - } else { - Some(completions) - } - }) - .map(|completions| { - completions.into_iter().map(|completion| format!("{:?}", completion)).collect() - }); - - // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic. - assert_eq!(completions, None, "Completions were generated, but weren't expected"); - } - - #[test] - fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { - check_detail_and_documentation( - r#" -macro_rules! bar { - () => { - struct Bar; - impl Bar { - #[doc = "Do the foo"] - fn foo(&self) {} - } - } -} - -bar!(); - -fn foo() { - let bar = Bar; - bar.fo$0; -} -"#, - DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, - ); - } - - #[test] - fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { - check_detail_and_documentation( - r#" -macro_rules! bar { - () => { - struct Bar; - impl Bar { - /// Do the foo - fn foo(&self) {} - } - } -} - -bar!(); - -fn foo() { - let bar = Bar; - bar.fo$0; -} -"#, - DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, - ); - } - - #[test] - fn test_no_completions_required() { - // There must be no hint for 'in' keyword. - check_no_completion(r#"fn foo() { for i i$0 }"#); - // After 'in' keyword hints may be spawned. - check_detail_and_documentation( - r#" -/// Do the foo -fn foo() -> &'static str { "foo" } - -fn bar() { - for c in fo$0 -} -"#, - DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" }, - ); - } -} diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 72e67e3c4cd..62e4334decd 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -11,7 +11,7 @@ use syntax::{ }; #[cfg(test)] -use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; +use crate::tests::{check_pattern_is_applicable, check_pattern_is_not_applicable}; /// Immediate previous node to what we are completing. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -19,6 +19,8 @@ pub(crate) enum ImmediatePrevSibling { IfExpr, TraitDefName, ImplDefType, + Visibility, + Attribute, } /// Direct parent "thing" of what we are currently completing. @@ -79,6 +81,17 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option node, }; let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; + if prev_sibling.kind() == ERROR { + let prev_sibling = prev_sibling.first_child()?; + let res = match_ast! { + match prev_sibling { + // vis followed by random ident will always error the parser + ast::Visibility(_it) => ImmediatePrevSibling::Visibility, + _ => return None, + } + }; + return Some(res); + } let res = match_ast! { match prev_sibling { ast::ExprStmt(it) => { @@ -101,6 +114,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option ImmediatePrevSibling::Attribute, _ => return None, } }; @@ -310,7 +324,7 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option { mod tests { use syntax::algo::find_node_at_offset; - use crate::test_utils::position; + use crate::tests::position; use super::*; @@ -421,4 +435,14 @@ mod tests { check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); check_prev_sibling(r"fn foo() { if true {}; w$0", None); } + + #[test] + fn test_vis_prev_sibling() { + check_prev_sibling(r"pub w$0", ImmediatePrevSibling::Visibility); + } + + #[test] + fn test_attr_prev_sibling() { + check_prev_sibling(r"#[attr] w$0", ImmediatePrevSibling::Attribute); + } } diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 2bd2c44d0a9..4b55f7504da 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -335,7 +335,7 @@ mod tests { use crate::{ item::CompletionRelevanceTypeMatch, - test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, + tests::{check_edit, do_completion, get_all_items, TEST_CONFIG}, CompletionKind, CompletionRelevance, }; diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 28f056e7758..91dc178f345 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs @@ -121,7 +121,7 @@ impl<'a> EnumRender<'a> { #[cfg(test)] mod tests { - use crate::test_utils::check_edit; + use crate::tests::check_edit; #[test] fn inserts_parens_for_tuple_enums() { diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 1357b9f4adf..19f2c86e9c4 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -191,7 +191,7 @@ impl<'a> FunctionRender<'a> { #[cfg(test)] mod tests { use crate::{ - test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, + tests::{check_edit, check_edit_with_config, TEST_CONFIG}, CompletionConfig, }; diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 3a7238bb812..d5a1f45d3e6 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs @@ -133,7 +133,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s #[cfg(test)] mod tests { - use crate::test_utils::check_edit; + use crate::tests::check_edit; #[test] fn dont_insert_macro_call_parens_unncessary() { diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/tests.rs similarity index 80% rename from crates/ide_completion/src/test_utils.rs rename to crates/ide_completion/src/tests.rs index b0a4b2026b0..1495924ea36 100644 --- a/crates/ide_completion/src/test_utils.rs +++ b/crates/ide_completion/src/tests.rs @@ -1,4 +1,4 @@ -//! Runs completion for testing purposes. +mod item_list; use hir::{PrefixKind, Semantics}; use ide_db::{ @@ -31,6 +31,14 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { }, }; +fn completion_list(code: &str) -> String { + completion_list_with_config(TEST_CONFIG, code) +} + +fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { + render_completion_list(get_all_items(config, code)) +} + /// Creates analysis from a multi-file fixture, returns positions marked with $0. pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { let change_fixture = ChangeFixture::parse(ra_fixture); @@ -57,24 +65,27 @@ pub(crate) fn do_completion_with_config( .collect() } -pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { - completion_list_with_config(TEST_CONFIG, code, kind) +pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String { + filtered_completion_list_with_config(TEST_CONFIG, code, kind) } -pub(crate) fn completion_list_with_config( +pub(crate) fn filtered_completion_list_with_config( config: CompletionConfig, code: &str, kind: CompletionKind, ) -> String { let kind_completions: Vec = get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); - let label_width = kind_completions - .iter() - .map(|it| monospace_width(it.label())) - .max() - .unwrap_or_default() - .min(16); - kind_completions + render_completion_list(kind_completions) +} + +fn render_completion_list(completions: Vec) -> String { + fn monospace_width(s: &str) -> usize { + s.chars().count() + } + let label_width = + completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(16); + completions .into_iter() .map(|it| { let tag = it.kind().unwrap().tag(); @@ -93,10 +104,6 @@ pub(crate) fn completion_list_with_config( .collect() } -fn monospace_width(s: &str) -> usize { - s.chars().count() -} - pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) } @@ -152,3 +159,18 @@ pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec