From d338a803941c2b0ac83decfcdfac33c09dfaa971 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 17:37:23 +0200 Subject: Start refactoring ide_completion tests --- crates/ide_completion/src/completions.rs | 113 +++++++------- crates/ide_completion/src/completions/keyword.rs | 36 ----- crates/ide_completion/src/completions/pattern.rs | 2 +- .../src/completions/qualified_path.rs | 18 --- crates/ide_completion/src/completions/snippet.rs | 17 -- .../src/completions/unqualified_path.rs | 2 +- crates/ide_completion/src/lib.rs | 125 +-------------- crates/ide_completion/src/tests.rs | 64 ++++++++ crates/ide_completion/src/tests/item_list.rs | 172 +++++++++++++++++++++ 9 files changed, 302 insertions(+), 247 deletions(-) create mode 100644 crates/ide_completion/src/tests.rs create mode 100644 crates/ide_completion/src/tests/item_list.rs (limited to 'crates') diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 783305005..cba5eb0c6 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,72 +115,102 @@ impl Completions { self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); } - pub(crate) fn add_variant_pat( + pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { + self.add_opt(render_const(RenderContext::new(ctx), constant)); + } + + pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { + self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); + } + + pub(crate) fn add_type_alias_with_eq( &mut self, ctx: &CompletionContext, - variant: hir::Variant, - local_name: Option, + type_alias: hir::TypeAlias, ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); + self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); } - pub(crate) fn add_qualified_variant_pat( + pub(crate) fn add_qualified_enum_variant( &mut self, ctx: &CompletionContext, variant: hir::Variant, path: hir::ModPath, ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); + let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); + self.add(item); } - pub(crate) fn add_struct_pat( + pub(crate) fn add_enum_variant( &mut self, ctx: &CompletionContext, - strukt: hir::Struct, + variant: hir::Variant, local_name: Option, ) { - self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); + let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); + self.add(item); } - pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { - self.add_opt(render_const(RenderContext::new(ctx), constant)); + 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_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { - self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); + 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_type_alias_with_eq( + 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, - type_alias: hir::TypeAlias, + variant: hir::Variant, + local_name: Option, ) { - self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); + self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); } - pub(crate) fn add_qualified_enum_variant( + pub(crate) fn add_qualified_variant_pat( &mut self, ctx: &CompletionContext, variant: hir::Variant, path: hir::ModPath, ) { - let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); - self.add(item); + self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); } - pub(crate) fn add_enum_variant( + pub(crate) fn add_struct_pat( &mut self, ctx: &CompletionContext, - variant: hir::Variant, + strukt: hir::Struct, local_name: Option, ) { - let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); - self.add(item); + 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/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0fccbeccf..2c42438d6 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -230,30 +230,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( @@ -442,18 +418,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/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 1daa8595a..e45b2a1ea 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); }); diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 1643eeed4..165b9e6a5 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -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/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index b9862de67..5560f1acf 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -105,21 +105,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/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index b5af1c810..2c623bf7a 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) }); } diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 18983aa01..be6442426 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -1,14 +1,16 @@ //! `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; +#[cfg(test)] +mod test_utils; use completions::flyimport::position_for_import; use ide_db::{ @@ -141,6 +143,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 +203,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/tests.rs b/crates/ide_completion/src/tests.rs new file mode 100644 index 000000000..4485a908e --- /dev/null +++ b/crates/ide_completion/src/tests.rs @@ -0,0 +1,64 @@ +mod item_list; + +use expect_test::Expect; +use stdx::format_to; + +use crate::{ + test_utils::{self, get_all_items, TEST_CONFIG}, + CompletionConfig, CompletionItem, +}; + +fn completion_list(code: &str) -> String { + completion_list_with_config(TEST_CONFIG, code) +} + +fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { + fn monospace_width(s: &str) -> usize { + s.chars().count() + } + + let kind_completions: Vec = get_all_items(config, code).into_iter().collect(); + let label_width = kind_completions + .iter() + .map(|it| monospace_width(it.label())) + .max() + .unwrap_or_default() + .min(16); + kind_completions + .into_iter() + .map(|it| { + let tag = it.kind().unwrap().tag(); + let var_name = format!("{} {}", tag, it.label()); + let mut buf = var_name; + if let Some(detail) = it.detail() { + let width = label_width.saturating_sub(monospace_width(it.label())); + format_to!(buf, "{:width$} {}", "", detail, width = width); + } + if it.deprecated() { + format_to!(buf, " DEPRECATED"); + } + format_to!(buf, "\n"); + buf + }) + .collect() +} + +fn check(ra_fixture: &str, expect: Expect) { + let actual = completion_list(ra_fixture); + expect.assert_eq(&actual) +} + +fn check_no_completion(ra_fixture: &str) { + let (db, position) = test_utils::position(ra_fixture); + + assert!( + crate::completions(&db, &TEST_CONFIG, position).is_none(), + "Completions were generated, but weren't expected" + ); +} + +#[test] +fn test_no_completions_required() { + cov_mark::check!(no_completion_required); + check_no_completion(r#"fn foo() { for i i$0 }"#); +} diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs new file mode 100644 index 000000000..bd060a632 --- /dev/null +++ b/crates/ide_completion/src/tests/item_list.rs @@ -0,0 +1,172 @@ +use expect_test::expect; + +use crate::tests::check; + +#[test] +fn in_mod_item_list() { + check( + r#"mod tests { + $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 + sn tmod (Test module) + sn tfn (Test function) + sn macro_rules + "#]], + ) +} + +#[test] +fn in_source_file_item_list() { + check( + r#" +enum Enum { Variant } +struct MyStruct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); + +$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 + sn tmod (Test module) + sn tfn (Test function) + sn macro_rules + md bar + ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ) +} + +#[test] +fn in_qualified_path() { + check( + r#" +enum Enum { Variant } +struct MyStruct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); + +crate::$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 + sn tmod (Test module) + sn tfn (Test function) + sn macro_rules + md bar + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ) +} + +#[test] +fn after_unsafe_token() { + check( + r#" +enum Enum { Variant } +struct MyStruct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); + +unsafe $0"#, + expect![[r##" + kw fn + kw trait + kw impl + sn tmod (Test module) + sn tfn (Test function) + sn macro_rules + md bar + ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ); +} + +#[test] +fn after_visibility() { + check( + r#" +enum Enum { Variant } +struct MyStruct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); + +pub $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 + sn tmod (Test module) + sn tfn (Test function) + sn macro_rules + md bar + ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ); +} -- cgit v1.2.3 From 1a8f76a224aff472cf29bab828f313c19e31eb02 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 17:45:58 +0200 Subject: Don't complete visibility accessors after existing ones --- crates/ide_completion/src/completions/keyword.rs | 4 +++- crates/ide_completion/src/context.rs | 4 ++++ crates/ide_completion/src/patterns.rs | 17 +++++++++++++++++ crates/ide_completion/src/tests/item_list.rs | 2 -- 4 files changed, 24 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 2c42438d6..0bfdf9603 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 "); } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index a8437d81c..3885db702 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -302,6 +302,10 @@ 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)) } diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 72e67e3c4..345977d48 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -19,6 +19,7 @@ pub(crate) enum ImmediatePrevSibling { IfExpr, TraitDefName, ImplDefType, + Visibility, } /// Direct parent "thing" of what we are currently completing. @@ -79,6 +80,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) => { @@ -421,4 +433,9 @@ 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); + } } diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs index bd060a632..e7b77d7e7 100644 --- a/crates/ide_completion/src/tests/item_list.rs +++ b/crates/ide_completion/src/tests/item_list.rs @@ -146,8 +146,6 @@ const CONST: () = (); pub $0"#, expect![[r##" - kw pub(crate) - kw pub kw unsafe kw fn kw const -- cgit v1.2.3 From 9ea6ee6b2785da02ff1963fbbc2eea340450905c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 17:56:04 +0200 Subject: Don't show incorrect completions after unsafe or visiblity node --- crates/ide_completion/src/completions/keyword.rs | 22 ++++++++------- crates/ide_completion/src/completions/snippet.rs | 7 ++++- crates/ide_completion/src/context.rs | 17 +++++++----- crates/ide_completion/src/tests/item_list.rs | 34 +++++++----------------- 4 files changed, 38 insertions(+), 42 deletions(-) (limited to 'crates') diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 0bfdf9603..7970e75c7 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -90,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"); } @@ -241,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 @@ -269,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 @@ -297,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 @@ -399,11 +401,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 diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 5560f1acf..4e64a0090 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]) { 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, diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 3885db702..907ffdc7a 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -311,13 +311,16 @@ impl<'a> CompletionContext<'a> { } 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]) + || self.has_visibility_prev_sibling() + || matches!( + self.completion_location, + Some(ImmediateLocation::Attribute(_)) + | Some(ImmediateLocation::ModDeclaration(_)) + | Some(ImmediateLocation::RecordPat(_)) + | Some(ImmediateLocation::RecordExpr(_)) + ) } pub(crate) fn expects_expression(&self) -> bool { diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs index e7b77d7e7..c8aa44d88 100644 --- a/crates/ide_completion/src/tests/item_list.rs +++ b/crates/ide_completion/src/tests/item_list.rs @@ -16,11 +16,11 @@ fn in_mod_item_list() { kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw enum kw struct @@ -51,11 +51,11 @@ $0"#, kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw enum kw struct @@ -89,11 +89,11 @@ crate::$0"#, kw fn kw const kw type - kw use kw impl + kw extern + kw use kw trait kw static - kw extern kw mod kw enum kw struct @@ -119,17 +119,11 @@ mod bar {} const CONST: () = (); unsafe $0"#, - expect![[r##" + expect![[r#" kw fn kw trait kw impl - sn tmod (Test module) - sn tfn (Test function) - sn macro_rules - md bar - ma foo!(…) #[macro_export] macro_rules! foo - ma foo!(…) #[macro_export] macro_rules! foo - "##]], + "#]], ); } @@ -145,26 +139,18 @@ mod bar {} const CONST: () = (); pub $0"#, - expect![[r##" + expect![[r#" 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 - sn tmod (Test module) - sn tfn (Test function) - sn macro_rules - md bar - ma foo!(…) #[macro_export] macro_rules! foo - ma foo!(…) #[macro_export] macro_rules! foo - "##]], + "#]], ); } -- cgit v1.2.3 From 11115ebad8d0cb367478a4f154abe08c0c25aa95 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 18:50:18 +0200 Subject: Don't complete paths after attributes --- crates/ide_completion/src/completions/keyword.rs | 43 ------- crates/ide_completion/src/completions/snippet.rs | 2 +- .../src/completions/unqualified_path.rs | 48 ------- crates/ide_completion/src/context.rs | 5 +- crates/ide_completion/src/patterns.rs | 7 + crates/ide_completion/src/tests.rs | 12 +- crates/ide_completion/src/tests/item_list.rs | 141 +++++++++++++++------ 7 files changed, 123 insertions(+), 135 deletions(-) (limited to 'crates') diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 7970e75c7..0a3df79d4 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -349,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( diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 4e64a0090..d142265e0 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -36,7 +36,7 @@ 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() || ctx.previous_token_is(T![unsafe]) { + if !ctx.expects_item() || ctx.previous_token_is(T![unsafe]) || ctx.path_qual().is_some() { return; } if ctx.has_visibility_prev_sibling() { diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 2c623bf7a..3910de2c4 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -500,18 +500,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 +760,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 907ffdc7a..441c080b1 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -313,7 +313,10 @@ impl<'a> CompletionContext<'a> { pub(crate) fn is_path_disallowed(&self) -> bool { self.attribute_under_caret.is_some() || self.previous_token_is(T![unsafe]) - || self.has_visibility_prev_sibling() + || matches!( + self.prev_sibling, + Some(ImmediatePrevSibling::Attribute) | Some(ImmediatePrevSibling::Visibility) + ) || matches!( self.completion_location, Some(ImmediateLocation::Attribute(_)) diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 345977d48..02cfe91e1 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs @@ -20,6 +20,7 @@ pub(crate) enum ImmediatePrevSibling { TraitDefName, ImplDefType, Visibility, + Attribute, } /// Direct parent "thing" of what we are currently completing. @@ -113,6 +114,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option ImmediatePrevSibling::Attribute, _ => return None, } }; @@ -438,4 +440,9 @@ mod tests { 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/tests.rs b/crates/ide_completion/src/tests.rs index 4485a908e..2205603fa 100644 --- a/crates/ide_completion/src/tests.rs +++ b/crates/ide_completion/src/tests.rs @@ -44,7 +44,17 @@ fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { } fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); + let base = r#"#[rustc_builtin_macro] +pub macro Clone {} +enum Enum { Variant } +struct Struct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); +trait Trait {} +"#; + let actual = completion_list(&format!("{}{}", base, ra_fixture)); expect.assert_eq(&actual) } diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs index c8aa44d88..33b23b8b4 100644 --- a/crates/ide_completion/src/tests/item_list.rs +++ b/crates/ide_completion/src/tests/item_list.rs @@ -9,7 +9,7 @@ fn in_mod_item_list() { $0 } "#, - expect![[r#" + expect![[r##" kw pub(crate) kw pub kw unsafe @@ -28,22 +28,15 @@ fn in_mod_item_list() { sn tmod (Test module) sn tfn (Test function) sn macro_rules - "#]], + ma foo!(…) #[macro_export] macro_rules! foo + "##]], ) } #[test] fn in_source_file_item_list() { check( - r#" -enum Enum { Variant } -struct MyStruct {} -#[macro_export] -macro_rules! foo {} -mod bar {} -const CONST: () = (); - -$0"#, + r#"$0"#, expect![[r##" kw pub(crate) kw pub @@ -71,18 +64,10 @@ $0"#, } #[test] -fn in_qualified_path() { +fn in_item_list_after_attr() { check( - r#" -enum Enum { Variant } -struct MyStruct {} -#[macro_export] -macro_rules! foo {} -mod bar {} -const CONST: () = (); - -crate::$0"#, - expect![[r##" + r#"#[attr] $0"#, + expect![[r#" kw pub(crate) kw pub kw unsafe @@ -101,8 +86,32 @@ crate::$0"#, sn tmod (Test module) sn tfn (Test function) sn macro_rules + "#]], + ) +} + +#[test] +fn in_qualified_path() { + check( + r#"crate::$0"#, + expect![[r##" + kw pub(crate) + kw pub + kw unsafe + kw fn + kw const + kw type + kw impl + kw extern + kw use + kw trait + kw static + kw mod + kw enum + kw struct + kw union md bar - ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo "##]], ) } @@ -110,15 +119,7 @@ crate::$0"#, #[test] fn after_unsafe_token() { check( - r#" -enum Enum { Variant } -struct MyStruct {} -#[macro_export] -macro_rules! foo {} -mod bar {} -const CONST: () = (); - -unsafe $0"#, + r#"unsafe $0"#, expect![[r#" kw fn kw trait @@ -130,15 +131,7 @@ unsafe $0"#, #[test] fn after_visibility() { check( - r#" -enum Enum { Variant } -struct MyStruct {} -#[macro_export] -macro_rules! foo {} -mod bar {} -const CONST: () = (); - -pub $0"#, + r#"pub $0"#, expect![[r#" kw unsafe kw fn @@ -154,3 +147,69 @@ pub $0"#, "#]], ); } + +#[test] +fn after_visibility_unsafe() { + // FIXME this shouldn't show `impl` + check( + r#"pub unsafe $0"#, + expect![[r#" + kw fn + kw trait + kw impl + "#]], + ); +} + +#[test] +fn in_impl_assoc_item_list() { + check( + r#"impl Struct { + $0 +}"#, + expect![[r##" + kw pub(crate) + kw pub + kw unsafe + kw fn + kw const + kw type + md bar + ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ) +} + +#[test] +fn in_impl_assoc_item_list_after_attr() { + check( + r#"impl Struct { + #[attr] $0 +}"#, + expect![[r#" + kw pub(crate) + kw pub + kw unsafe + kw fn + kw const + kw type + "#]], + ) +} + +#[test] +fn in_trait_assoc_item_list() { + check( + r"trait Foo { $0 }", + expect![[r##" + kw unsafe + kw fn + kw const + kw type + md bar + ma foo!(…) #[macro_export] macro_rules! foo + ma foo!(…) #[macro_export] macro_rules! foo + "##]], + ); +} -- cgit v1.2.3 From aa644b55859c6b5c6695a5d4fb35d1b6efbbebcc Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 16 Jun 2021 21:45:02 +0200 Subject: Move test_utils into tests module --- crates/ide_completion/src/completions/attribute.rs | 4 +- .../src/completions/attribute/derive.rs | 4 +- .../src/completions/attribute/lint.rs | 2 +- crates/ide_completion/src/completions/dot.rs | 4 +- crates/ide_completion/src/completions/flyimport.rs | 4 +- crates/ide_completion/src/completions/fn_param.rs | 4 +- crates/ide_completion/src/completions/keyword.rs | 4 +- crates/ide_completion/src/completions/lifetime.rs | 5 +- crates/ide_completion/src/completions/mod_.rs | 4 +- crates/ide_completion/src/completions/pattern.rs | 6 +- crates/ide_completion/src/completions/postfix.rs | 4 +- .../src/completions/qualified_path.rs | 6 +- crates/ide_completion/src/completions/record.rs | 8 +- crates/ide_completion/src/completions/snippet.rs | 4 +- .../ide_completion/src/completions/trait_impl.rs | 4 +- .../src/completions/unqualified_path.rs | 5 +- crates/ide_completion/src/context.rs | 2 +- crates/ide_completion/src/lib.rs | 2 - crates/ide_completion/src/patterns.rs | 4 +- crates/ide_completion/src/render.rs | 2 +- crates/ide_completion/src/render/enum_variant.rs | 2 +- crates/ide_completion/src/render/function.rs | 2 +- crates/ide_completion/src/render/macro_.rs | 2 +- crates/ide_completion/src/test_utils.rs | 154 -------------------- crates/ide_completion/src/tests.rs | 158 +++++++++++++++++---- crates/ide_completion/src/tests/item_list.rs | 32 +++-- 26 files changed, 194 insertions(+), 238 deletions(-) delete mode 100644 crates/ide_completion/src/test_utils.rs (limited to 'crates') diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 6df569c2a..3866c5917 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 20bbbba46..5201095e8 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 ca99e9759..4812b075c 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 9552875c1..7f75d4298 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 30b8d44bd..4604feb5d 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 cb90e8a3e..c9f0e2473 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 0a3df79d4..73bbc4345 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -190,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) } diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 8ccccb646..36f595164 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 6a5746fb9..5def0d06a 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 e45b2a1ea..efe3c957a 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs @@ -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 9f98b21be..c3c7e4589 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 165b9e6a5..9432caa22 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); } diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 0ac47cdbe..47523f72f 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 d142265e0..81ddfa34f 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -87,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) } diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a60e5f43c..dc1d198cc 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 3910de2c4..2868d9b18 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -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) } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 441c080b1..121909857 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -695,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 be6442426..bf73818dc 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -9,8 +9,6 @@ mod render; #[cfg(test)] mod tests; -#[cfg(test)] -mod test_utils; use completions::flyimport::position_for_import; use ide_db::{ diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 02cfe91e1..62e4334de 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)] @@ -324,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::*; diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 2bd2c44d0..4b55f7504 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 28f056e77..91dc178f3 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 1357b9f4a..19f2c86e9 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 3a7238bb8..d5a1f45d3 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/test_utils.rs deleted file mode 100644 index b0a4b2026..000000000 --- a/crates/ide_completion/src/test_utils.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Runs completion for testing purposes. - -use hir::{PrefixKind, Semantics}; -use ide_db::{ - base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, - helpers::{ - insert_use::{ImportGranularity, InsertUseConfig}, - SnippetCap, - }, - RootDatabase, -}; -use itertools::Itertools; -use stdx::{format_to, trim_indent}; -use syntax::{AstNode, NodeOrToken, SyntaxElement}; -use test_utils::assert_eq_text; - -use crate::{item::CompletionKind, CompletionConfig, CompletionItem}; - -pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { - enable_postfix_completions: true, - enable_imports_on_the_fly: true, - enable_self_on_the_fly: true, - add_call_parenthesis: true, - add_call_argument_snippets: true, - snippet_cap: SnippetCap::new(true), - insert_use: InsertUseConfig { - granularity: ImportGranularity::Crate, - prefix_kind: PrefixKind::Plain, - enforce_granularity: true, - group: true, - }, -}; - -/// 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); - let mut database = RootDatabase::default(); - database.apply_change(change_fixture.change); - let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - let offset = range_or_offset.expect_offset(); - (database, FilePosition { file_id, offset }) -} - -pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec { - do_completion_with_config(TEST_CONFIG, code, kind) -} - -pub(crate) fn do_completion_with_config( - config: CompletionConfig, - code: &str, - kind: CompletionKind, -) -> Vec { - get_all_items(config, code) - .into_iter() - .filter(|c| c.completion_kind == kind) - .sorted_by(|l, r| l.label().cmp(r.label())) - .collect() -} - -pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { - completion_list_with_config(TEST_CONFIG, code, kind) -} - -pub(crate) fn 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 - .into_iter() - .map(|it| { - let tag = it.kind().unwrap().tag(); - let var_name = format!("{} {}", tag, it.label()); - let mut buf = var_name; - if let Some(detail) = it.detail() { - let width = label_width.saturating_sub(monospace_width(it.label())); - format_to!(buf, "{:width$} {}", "", detail, width = width); - } - if it.deprecated() { - format_to!(buf, " DEPRECATED"); - } - format_to!(buf, "\n"); - buf - }) - .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) -} - -pub(crate) fn check_edit_with_config( - config: CompletionConfig, - what: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, -) { - let ra_fixture_after = trim_indent(ra_fixture_after); - let (db, position) = position(ra_fixture_before); - let completions: Vec = - crate::completions(&db, &config, position).unwrap().into(); - let (completion,) = completions - .iter() - .filter(|it| it.lookup() == what) - .collect_tuple() - .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions)); - let mut actual = db.file_text(position.file_id).to_string(); - - let mut combined_edit = completion.text_edit().to_owned(); - if let Some(import_text_edit) = - completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use)) - { - combined_edit.union(import_text_edit).expect( - "Failed to apply completion resolve changes: change ranges overlap, but should not", - ) - } - - combined_edit.apply(&mut actual); - assert_eq_text!(&ra_fixture_after, &actual) -} - -pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) { - let (db, pos) = position(code); - - let sema = Semantics::new(&db); - let original_file = sema.parse(pos.file_id); - let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); - assert!(check(NodeOrToken::Token(token))); -} - -pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElement) -> bool) { - let (db, pos) = position(code); - let sema = Semantics::new(&db); - let original_file = sema.parse(pos.file_id); - let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); - assert!(!check(NodeOrToken::Token(token))); -} - -pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec { - let (db, position) = position(code); - crate::completions(&db, &config, position).unwrap().into() -} diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs index 2205603fa..1495924ea 100644 --- a/crates/ide_completion/src/tests.rs +++ b/crates/ide_completion/src/tests.rs @@ -1,11 +1,34 @@ mod item_list; -use expect_test::Expect; -use stdx::format_to; +use hir::{PrefixKind, Semantics}; +use ide_db::{ + base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, + helpers::{ + insert_use::{ImportGranularity, InsertUseConfig}, + SnippetCap, + }, + RootDatabase, +}; +use itertools::Itertools; +use stdx::{format_to, trim_indent}; +use syntax::{AstNode, NodeOrToken, SyntaxElement}; +use test_utils::assert_eq_text; + +use crate::{item::CompletionKind, CompletionConfig, CompletionItem}; -use crate::{ - test_utils::{self, get_all_items, TEST_CONFIG}, - CompletionConfig, CompletionItem, +pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { + enable_postfix_completions: true, + enable_imports_on_the_fly: true, + enable_self_on_the_fly: true, + add_call_parenthesis: true, + add_call_argument_snippets: true, + snippet_cap: SnippetCap::new(true), + insert_use: InsertUseConfig { + granularity: ImportGranularity::Crate, + prefix_kind: PrefixKind::Plain, + enforce_granularity: true, + group: true, + }, }; fn completion_list(code: &str) -> String { @@ -13,18 +36,56 @@ fn completion_list(code: &str) -> String { } 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); + let mut database = RootDatabase::default(); + database.apply_change(change_fixture.change); + let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); + let offset = range_or_offset.expect_offset(); + (database, FilePosition { file_id, offset }) +} + +pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec { + do_completion_with_config(TEST_CONFIG, code, kind) +} + +pub(crate) fn do_completion_with_config( + config: CompletionConfig, + code: &str, + kind: CompletionKind, +) -> Vec { + get_all_items(config, code) + .into_iter() + .filter(|c| c.completion_kind == kind) + .sorted_by(|l, r| l.label().cmp(r.label())) + .collect() +} + +pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String { + filtered_completion_list_with_config(TEST_CONFIG, code, kind) +} + +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(); + render_completion_list(kind_completions) +} + +fn render_completion_list(completions: Vec) -> String { fn monospace_width(s: &str) -> usize { s.chars().count() } - - let kind_completions: Vec = get_all_items(config, code).into_iter().collect(); - let label_width = kind_completions - .iter() - .map(|it| monospace_width(it.label())) - .max() - .unwrap_or_default() - .min(16); - kind_completions + 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(); @@ -43,23 +104,64 @@ fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { .collect() } -fn check(ra_fixture: &str, expect: Expect) { - let base = r#"#[rustc_builtin_macro] -pub macro Clone {} -enum Enum { Variant } -struct Struct {} -#[macro_export] -macro_rules! foo {} -mod bar {} -const CONST: () = (); -trait Trait {} -"#; - let actual = completion_list(&format!("{}{}", base, ra_fixture)); - expect.assert_eq(&actual) +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) +} + +pub(crate) fn check_edit_with_config( + config: CompletionConfig, + what: &str, + ra_fixture_before: &str, + ra_fixture_after: &str, +) { + let ra_fixture_after = trim_indent(ra_fixture_after); + let (db, position) = position(ra_fixture_before); + let completions: Vec = + crate::completions(&db, &config, position).unwrap().into(); + let (completion,) = completions + .iter() + .filter(|it| it.lookup() == what) + .collect_tuple() + .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions)); + let mut actual = db.file_text(position.file_id).to_string(); + + let mut combined_edit = completion.text_edit().to_owned(); + if let Some(import_text_edit) = + completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use)) + { + combined_edit.union(import_text_edit).expect( + "Failed to apply completion resolve changes: change ranges overlap, but should not", + ) + } + + combined_edit.apply(&mut actual); + assert_eq_text!(&ra_fixture_after, &actual) +} + +pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) { + let (db, pos) = position(code); + + let sema = Semantics::new(&db); + let original_file = sema.parse(pos.file_id); + let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); + assert!(check(NodeOrToken::Token(token))); +} + +pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElement) -> bool) { + let (db, pos) = position(code); + let sema = Semantics::new(&db); + let original_file = sema.parse(pos.file_id); + let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap(); + assert!(!check(NodeOrToken::Token(token))); +} + +pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec { + let (db, position) = position(code); + crate::completions(&db, &config, position).unwrap().into() } fn check_no_completion(ra_fixture: &str) { - let (db, position) = test_utils::position(ra_fixture); + let (db, position) = position(ra_fixture); assert!( crate::completions(&db, &TEST_CONFIG, position).is_none(), diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs index 33b23b8b4..7c124ac37 100644 --- a/crates/ide_completion/src/tests/item_list.rs +++ b/crates/ide_completion/src/tests/item_list.rs @@ -1,14 +1,26 @@ -use expect_test::expect; +use expect_test::{expect, Expect}; -use crate::tests::check; +use crate::tests::completion_list; + +fn check(ra_fixture: &str, expect: Expect) { + let base = r#"#[rustc_builtin_macro] +pub macro Clone {} +enum Enum { Variant } +struct Struct {} +#[macro_export] +macro_rules! foo {} +mod bar {} +const CONST: () = (); +trait Trait {} +"#; + let actual = completion_list(&format!("{}{}", base, ra_fixture)); + expect.assert_eq(&actual) +} #[test] fn in_mod_item_list() { check( - r#"mod tests { - $0 -} -"#, + r#"mod tests { $0 }"#, expect![[r##" kw pub(crate) kw pub @@ -164,9 +176,7 @@ fn after_visibility_unsafe() { #[test] fn in_impl_assoc_item_list() { check( - r#"impl Struct { - $0 -}"#, + r#"impl Struct { $0 }"#, expect![[r##" kw pub(crate) kw pub @@ -184,9 +194,7 @@ fn in_impl_assoc_item_list() { #[test] fn in_impl_assoc_item_list_after_attr() { check( - r#"impl Struct { - #[attr] $0 -}"#, + r#"impl Struct { #[attr] $0 }"#, expect![[r#" kw pub(crate) kw pub -- cgit v1.2.3