diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 81bb59681ba..1bcbb3aaa65 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -357,6 +357,12 @@ impl Completions { variant: hir::Variant, local_name: Option, ) { + if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx { + cov_mark::hit!(enum_variant_pattern_path); + self.add_variant_pat(ctx, pat_ctx, variant, local_name); + return; + } + if let Some(builder) = render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None) { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 058d0ab7bb5..df0556ba451 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -115,6 +115,7 @@ pub(crate) fn complete_expr_path( }; if let Some(hir::Adt::Enum(e)) = ty.as_adt() { + cov_mark::hit!(completes_variant_through_self); acc.add_enum_variants(ctx, path_ctx, e); } diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 7a344c2c7b3..65b6eee1888 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -151,7 +151,6 @@ pub(crate) fn complete_pattern_path( }; if let Some(hir::Adt::Enum(e)) = ty.as_adt() { - cov_mark::hit!(enum_plain_qualified_use_tree); acc.add_enum_variants(ctx, path_ctx, e); } diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs index c98590f1361..e5689f332dd 100644 --- a/crates/ide-completion/src/completions/use_.rs +++ b/crates/ide-completion/src/completions/use_.rs @@ -79,9 +79,7 @@ pub(crate) fn complete_use_path( } hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { cov_mark::hit!(enum_plain_qualified_use_tree); - e.variants(ctx.db) - .into_iter() - .for_each(|variant| acc.add_enum_variant(ctx, path_ctx, variant, None)); + acc.add_enum_variants(ctx, path_ctx, *e); } _ => {} } diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index f9c4037dee4..d6779961c07 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -7,7 +7,10 @@ use syntax::SmolStr; use crate::{ context::{ParamKind, PatternContext}, - render::{variant::visible_fields, RenderContext}, + render::{ + variant::{format_literal_label, visible_fields}, + RenderContext, + }, CompletionItem, CompletionItemKind, }; @@ -29,16 +32,11 @@ pub(crate) fn render_struct_pat( let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())); let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); - let pat = render_pat( - &ctx, - pattern_ctx, - &escaped_name, - strukt.kind(ctx.db()), - &visible_fields, - fields_omitted, - )?; + let kind = strukt.kind(ctx.db()); + let label = format_literal_label(name.as_str(), kind); + let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - Some(build_completion(ctx, name, pat, strukt)) + Some(build_completion(ctx, label, pat, strukt)) } pub(crate) fn render_variant_pat( @@ -60,25 +58,20 @@ pub(crate) fn render_variant_pat( (name.to_smol_str(), name.escaped().to_smol_str()) } }; - let pat = render_pat( - &ctx, - pattern_ctx, - &escaped_name, - variant.kind(ctx.db()), - &visible_fields, - fields_omitted, - )?; + let kind = variant.kind(ctx.db()); + let label = format_literal_label(name.as_str(), kind); + let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - Some(build_completion(ctx, name, pat, variant)) + Some(build_completion(ctx, label, pat, variant)) } fn build_completion( ctx: RenderContext<'_>, - name: SmolStr, + label: SmolStr, pat: String, def: impl HasAttrs + Copy, ) -> CompletionItem { - let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), name); + let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label); item.set_documentation(ctx.docs(def)) .set_deprecated(ctx.is_deprecated(def)) .detail(&pat) @@ -103,7 +96,7 @@ fn render_pat( StructKind::Record => { render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted) } - StructKind::Unit => return None, + StructKind::Unit => name.to_string(), }; let needs_ascription = matches!( @@ -138,7 +131,7 @@ fn render_record_as_pat( format!( "{name} {{ {}{} }}", fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db), idx + 1)) + f(&format_args!("{}${}", field.name(db).escaped(), idx + 1)) }), if fields_omitted { ", .." } else { "" }, name = name @@ -147,7 +140,7 @@ fn render_record_as_pat( None => { format!( "{name} {{ {}{} }}", - fields.map(|field| field.name(db)).format(", "), + fields.map(|field| field.name(db).escaped().to_smol_str()).format(", "), if fields_omitted { ", .." } else { "" }, name = name ) diff --git a/crates/ide-completion/src/tests/fn_param.rs b/crates/ide-completion/src/tests/fn_param.rs index f5a5b5bae6a..cce74604c2d 100644 --- a/crates/ide-completion/src/tests/fn_param.rs +++ b/crates/ide-completion/src/tests/fn_param.rs @@ -139,8 +139,8 @@ fn foo2($0) {} "#, expect![[r#" st Bar - bn Bar Bar { bar$1 }: Bar$0 bn Bar { bar }: Bar + bn Bar {…} Bar { bar$1 }: Bar$0 kw mut kw ref "#]], diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs index 7169209d810..63ccf9003b4 100644 --- a/crates/ide-completion/src/tests/pattern.rs +++ b/crates/ide-completion/src/tests/pattern.rs @@ -1,7 +1,7 @@ //! Completion tests for pattern position. use expect_test::{expect, Expect}; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; fn check_empty(ra_fixture: &str, expect: Expect) { let actual = completion_list(ra_fixture); @@ -127,15 +127,15 @@ fn foo() { expect![[r#" ct CONST en Enum - ma makro!(…) macro_rules! makro + ma makro!(…) macro_rules! makro md module st Record st Tuple st Unit ev TupleV - bn Record Record { field$1 }$0 - bn Tuple Tuple($1)$0 - bn TupleV TupleV($1)$0 + bn Record {…} Record { field$1 }$0 + bn Tuple(…) Tuple($1)$0 + bn TupleV(…) TupleV($1)$0 kw mut kw ref "#]], @@ -162,8 +162,9 @@ fn foo() { st Tuple st Unit ev Variant - bn Record Record { field$1 }$0 - bn Tuple Tuple($1)$0 + bn Record {…} Record { field$1 }$0 + bn Tuple(…) Tuple($1)$0 + bn Variant Variant$0 kw mut kw ref "#]], @@ -178,13 +179,13 @@ fn foo(a$0) { } "#, expect![[r#" - ma makro!(…) macro_rules! makro + ma makro!(…) macro_rules! makro md module st Record st Tuple st Unit - bn Record Record { field$1 }: Record$0 - bn Tuple Tuple($1): Tuple$0 + bn Record {…} Record { field$1 }: Record$0 + bn Tuple(…) Tuple($1): Tuple$0 kw mut kw ref "#]], @@ -195,13 +196,13 @@ fn foo(a$0: Tuple) { } "#, expect![[r#" - ma makro!(…) macro_rules! makro + ma makro!(…) macro_rules! makro md module st Record st Tuple st Unit - bn Record Record { field$1 }$0 - bn Tuple Tuple($1)$0 + bn Record {…} Record { field$1 }$0 + bn Tuple(…) Tuple($1)$0 kw mut kw ref "#]], @@ -243,6 +244,7 @@ fn foo() { expect![[r#" en E ma m!(…) macro_rules! m + bn E::X E::X$0 kw mut kw ref "#]], @@ -269,8 +271,8 @@ fn outer() { st Invisible st Record st Tuple - bn Record Record { field$1, .. }$0 - bn Tuple Tuple($1, ..)$0 + bn Record {…} Record { field$1, .. }$0 + bn Tuple(…) Tuple($1, ..)$0 kw mut kw ref "#]], @@ -293,8 +295,8 @@ impl Foo { expect![[r#" sp Self st Foo - bn Foo Foo($1)$0 - bn Self Self($1)$0 + bn Foo(…) Foo($1)$0 + bn Self(…) Self($1)$0 kw mut kw ref "#]], @@ -316,9 +318,9 @@ fn func() { "#, expect![[r#" ct ASSOC_CONST const ASSOC_CONST: () - ev RecordV {…} RecordV { field: u32 } - ev TupleV(…) TupleV(u32) - ev UnitV UnitV + bn RecordV {…} RecordV { field$1 }$0 + bn TupleV(…) TupleV($1)$0 + bn UnitV UnitV$0 "#]], ); } @@ -334,8 +336,8 @@ fn outer(Foo { bar: $0 }: Foo) {} expect![[r#" st Bar st Foo - bn Bar Bar($1)$0 - bn Foo Foo { bar$1 }$0 + bn Bar(…) Bar($1)$0 + bn Foo {…} Foo { bar$1 }$0 kw mut kw ref "#]], @@ -368,8 +370,8 @@ fn foo($0) {} expect![[r#" st Bar st Foo - bn Bar Bar($1): Bar$0 - bn Foo Foo { bar$1 }: Foo$0 + bn Bar(…) Bar($1): Bar$0 + bn Foo {…} Foo { bar$1 }: Foo$0 kw mut kw ref "#]], @@ -389,8 +391,8 @@ fn foo() { expect![[r#" st Bar st Foo - bn Bar Bar($1)$0 - bn Foo Foo { bar$1 }$0 + bn Bar(…) Bar($1)$0 + bn Foo {…} Foo { bar$1 }$0 kw mut kw ref "#]], @@ -443,7 +445,7 @@ fn foo() { } "#, expect![[r#" - ev TupleVariant TupleVariant + bn TupleVariant(…) TupleVariant($1)$0 "#]], ); check_empty( @@ -458,7 +460,86 @@ fn foo() { } "#, expect![[r#" - ev RecordVariant RecordVariant + bn RecordVariant {…} RecordVariant { field$1 }$0 + "#]], + ); +} + +#[test] +fn completes_enum_variant_pat() { + cov_mark::check!(enum_variant_pattern_path); + check_edit( + "RecordVariant {…}", + r#" +enum Enum { + RecordVariant { field: u32 } +} +fn foo() { + match (Enum::RecordVariant { field: 0 }) { + Enum::RecordV$0 + } +} +"#, + r#" +enum Enum { + RecordVariant { field: u32 } +} +fn foo() { + match (Enum::RecordVariant { field: 0 }) { + Enum::RecordVariant { field$1 }$0 + } +} +"#, + ); +} + +#[test] +fn completes_enum_variant_pat_escape() { + cov_mark::check!(enum_variant_pattern_path); + check_empty( + r#" +enum Enum { + A, + B { r#type: i32 }, + r#type, + r#struct { r#type: i32 }, +} +fn foo() { + match (Enum::A) { + $0 + } +} +"#, + expect![[r#" + en Enum + bn Enum::A Enum::A$0 + bn Enum::B {…} Enum::B { r#type$1 }$0 + bn Enum::struct {…} Enum::r#struct { r#type$1 }$0 + bn Enum::type Enum::r#type$0 + kw mut + kw ref + "#]], + ); + + check_empty( + r#" +enum Enum { + A, + B { r#type: i32 }, + r#type, + r#struct { r#type: i32 }, +} +fn foo() { + match (Enum::A) { + Enum::$0 + } +} +"#, + expect![[r#" + bn A A$0 + bn B {…} B { r#type$1 }$0 + bn struct {…} r#struct { r#type$1 }$0 + bn type r#type$0 "#]], ); } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 96d0219fef6..fc59f781dd3 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -519,6 +519,7 @@ fn foo() { #[test] fn completes_variant_through_self() { + cov_mark::check!(completes_variant_through_self); check( r#" enum Foo { diff --git a/crates/ide-completion/src/tests/use_tree.rs b/crates/ide-completion/src/tests/use_tree.rs index 3134915bdab..109007c7a07 100644 --- a/crates/ide-completion/src/tests/use_tree.rs +++ b/crates/ide-completion/src/tests/use_tree.rs @@ -165,30 +165,15 @@ fn enum_plain_qualified_use_tree() { r#" use Foo::$0 -enum Foo { Variant } -impl Foo { - const CONST: () = () - fn func() {} -} -"#, - expect![[r#" - ev Variant Variant - "#]], - ); -} - -#[test] -fn enum_no_parens_in_qualified_use_tree() { - cov_mark::check!(enum_plain_qualified_use_tree); - check( - r#" -use Foo::$0 - enum Foo { UnitVariant, TupleVariant(), RecordVariant {}, } +impl Foo { + const CONST: () = () + fn func() {} +} "#, expect![[r#" ev RecordVariant RecordVariant