| //! Completion tests for pattern position. |
| use expect_test::{expect, Expect}; |
| |
| use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; |
| |
| fn check(ra_fixture: &str, expect: Expect) { |
| let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); |
| expect.assert_eq(&actual) |
| } |
| |
| #[test] |
| fn wildcard() { |
| check( |
| r#" |
| fn quux() { |
| let _$0 |
| } |
| "#, |
| expect![""], |
| ); |
| } |
| |
| #[test] |
| fn ident_rebind_pat() { |
| check_empty( |
| r#" |
| fn quux() { |
| let en$0 @ x |
| } |
| "#, |
| expect![[r#" |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn ident_ref_pat() { |
| check_empty( |
| r#" |
| fn quux() { |
| let ref en$0 |
| } |
| "#, |
| expect![[r#" |
| kw mut |
| "#]], |
| ); |
| check_empty( |
| r#" |
| fn quux() { |
| let ref en$0 @ x |
| } |
| "#, |
| expect![[r#" |
| kw mut |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn ident_ref_mut_pat() { |
| check_empty( |
| r#" |
| fn quux() { |
| let ref mut en$0 |
| } |
| "#, |
| expect![[r#""#]], |
| ); |
| check_empty( |
| r#" |
| fn quux() { |
| let ref mut en$0 @ x |
| } |
| "#, |
| expect![[r#""#]], |
| ); |
| } |
| |
| #[test] |
| fn ref_pat() { |
| check_empty( |
| r#" |
| fn quux() { |
| let &en$0 |
| } |
| "#, |
| expect![[r#" |
| kw mut |
| "#]], |
| ); |
| check_empty( |
| r#" |
| fn quux() { |
| let &mut en$0 |
| } |
| "#, |
| expect![[r#""#]], |
| ); |
| check_empty( |
| r#" |
| fn foo() { |
| for &$0 in () {} |
| } |
| "#, |
| expect![[r#" |
| kw mut |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn refutable() { |
| check( |
| r#" |
| fn foo() { |
| if let a$0 |
| } |
| "#, |
| expect![[r#" |
| ct CONST |
| en Enum |
| 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 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn irrefutable() { |
| check( |
| r#" |
| enum SingleVariantEnum { |
| Variant |
| } |
| use SingleVariantEnum::Variant; |
| fn foo() { |
| let a$0 |
| } |
| "#, |
| expect![[r#" |
| en SingleVariantEnum |
| ma makro!(…) macro_rules! makro |
| md module |
| st Record |
| st Tuple |
| st Unit |
| ev Variant |
| bn Record {…} Record { field$1 }$0 |
| bn Tuple(…) Tuple($1)$0 |
| bn Variant Variant$0 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn in_param() { |
| check( |
| r#" |
| fn foo(a$0) { |
| } |
| "#, |
| expect![[r#" |
| 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 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| check( |
| r#" |
| fn foo(a$0: Tuple) { |
| } |
| "#, |
| expect![[r#" |
| ma makro!(…) macro_rules! makro |
| md module |
| st Record |
| st Tuple |
| st Unit |
| bn Record {…} Record { field$1 }$0 |
| bn Tuple(…) Tuple($1)$0 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn only_fn_like_macros() { |
| check_empty( |
| r#" |
| macro_rules! m { ($e:expr) => { $e } } |
| |
| #[rustc_builtin_macro] |
| macro Clone {} |
| |
| fn foo() { |
| let x$0 |
| } |
| "#, |
| expect![[r#" |
| ma m!(…) macro_rules! m |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn in_simple_macro_call() { |
| check_empty( |
| r#" |
| macro_rules! m { ($e:expr) => { $e } } |
| enum E { X } |
| |
| fn foo() { |
| m!(match E::X { a$0 }) |
| } |
| "#, |
| expect![[r#" |
| en E |
| ma m!(…) macro_rules! m |
| bn E::X E::X$0 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn omits_private_fields_pat() { |
| check_empty( |
| r#" |
| mod foo { |
| pub struct Record { pub field: i32, _field: i32 } |
| pub struct Tuple(pub u32, u32); |
| pub struct Invisible(u32, u32); |
| } |
| use foo::*; |
| |
| fn outer() { |
| if let a$0 |
| } |
| "#, |
| expect![[r#" |
| md foo |
| st Invisible |
| st Record |
| st Tuple |
| bn Record {…} Record { field$1, .. }$0 |
| bn Tuple(…) Tuple($1, ..)$0 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_self_pats() { |
| check_empty( |
| r#" |
| struct Foo(i32); |
| impl Foo { |
| fn foo() { |
| match Foo(0) { |
| a$0 |
| } |
| } |
| } |
| "#, |
| expect![[r#" |
| sp Self |
| st Foo |
| bn Foo(…) Foo($1)$0 |
| bn Self(…) Self($1)$0 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn enum_qualified() { |
| check( |
| r#" |
| impl Enum { |
| type AssocType = (); |
| const ASSOC_CONST: () = (); |
| fn assoc_fn() {} |
| } |
| fn func() { |
| if let Enum::$0 = unknown {} |
| } |
| "#, |
| expect![[r#" |
| ct ASSOC_CONST const ASSOC_CONST: () |
| bn RecordV {…} RecordV { field$1 }$0 |
| bn TupleV(…) TupleV($1)$0 |
| bn UnitV UnitV$0 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_in_record_field_pat() { |
| check_empty( |
| r#" |
| struct Foo { bar: Bar } |
| struct Bar(u32); |
| fn outer(Foo { bar: $0 }: Foo) {} |
| "#, |
| expect![[r#" |
| st Bar |
| st Foo |
| bn Bar(…) Bar($1)$0 |
| bn Foo {…} Foo { bar$1 }$0 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn skips_in_record_field_pat_name() { |
| check_empty( |
| r#" |
| struct Foo { bar: Bar } |
| struct Bar(u32); |
| fn outer(Foo { bar$0 }: Foo) {} |
| "#, |
| expect![[r#" |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_in_record_field_pat_with_generic_type_alias() { |
| check_empty( |
| r#" |
| type Wrap<T> = T; |
| |
| enum X { |
| A { cool: u32, stuff: u32 }, |
| B, |
| } |
| |
| fn main() { |
| let wrapped = Wrap::<X>::A { |
| cool: 100, |
| stuff: 100, |
| }; |
| |
| if let Wrap::<X>::A { $0 } = &wrapped {}; |
| } |
| "#, |
| expect![[r#" |
| fd cool u32 |
| fd stuff u32 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_in_fn_param() { |
| check_empty( |
| r#" |
| struct Foo { bar: Bar } |
| struct Bar(u32); |
| fn foo($0) {} |
| "#, |
| expect![[r#" |
| st Bar |
| st Foo |
| bn Bar(…) Bar($1): Bar$0 |
| bn Foo {…} Foo { bar$1 }: Foo$0 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_in_closure_param() { |
| check_empty( |
| r#" |
| struct Foo { bar: Bar } |
| struct Bar(u32); |
| fn foo() { |
| |$0| {}; |
| } |
| "#, |
| expect![[r#" |
| st Bar |
| st Foo |
| bn Bar(…) Bar($1)$0 |
| bn Foo {…} Foo { bar$1 }$0 |
| kw mut |
| kw ref |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_no_delims_if_existing() { |
| check_empty( |
| r#" |
| struct Bar(u32); |
| fn foo() { |
| match Bar(0) { |
| B$0(b) => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| st Bar Bar |
| kw crate:: |
| kw self:: |
| "#]], |
| ); |
| check_empty( |
| r#" |
| struct Foo { bar: u32 } |
| fn foo() { |
| match (Foo { bar: 0 }) { |
| F$0 { bar } => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| st Foo Foo |
| kw crate:: |
| kw self:: |
| "#]], |
| ); |
| check_empty( |
| r#" |
| enum Enum { |
| TupleVariant(u32) |
| } |
| fn foo() { |
| match Enum::TupleVariant(0) { |
| Enum::T$0(b) => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| bn TupleVariant TupleVariant |
| "#]], |
| ); |
| check_empty( |
| r#" |
| enum Enum { |
| RecordVariant { field: u32 } |
| } |
| fn foo() { |
| match (Enum::RecordVariant { field: 0 }) { |
| Enum::RecordV$0 { field } => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| bn RecordVariant RecordVariant |
| "#]], |
| ); |
| } |
| |
| #[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 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_associated_const() { |
| check_empty( |
| r#" |
| #[derive(PartialEq, Eq)] |
| struct Ty(u8); |
| |
| impl Ty { |
| const ABC: Self = Self(0); |
| } |
| |
| fn f(t: Ty) { |
| match t { |
| Ty::$0 => {} |
| _ => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| ct ABC const ABC: Self |
| "#]], |
| ); |
| |
| check_empty( |
| r#" |
| enum MyEnum {} |
| |
| impl MyEnum { |
| pub const A: i32 = 123; |
| pub const B: i32 = 456; |
| } |
| |
| fn f(e: MyEnum) { |
| match e { |
| MyEnum::$0 => {} |
| _ => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| ct A pub const A: i32 |
| ct B pub const B: i32 |
| "#]], |
| ); |
| |
| check_empty( |
| r#" |
| union U { |
| i: i32, |
| f: f32, |
| } |
| |
| impl U { |
| pub const C: i32 = 123; |
| pub const D: i32 = 456; |
| } |
| |
| fn f(u: U) { |
| match u { |
| U::$0 => {} |
| _ => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| ct C pub const C: i32 |
| ct D pub const D: i32 |
| "#]], |
| ); |
| |
| check_empty( |
| r#" |
| #![rustc_coherence_is_core] |
| #[lang = "u32"] |
| impl u32 { |
| pub const MIN: Self = 0; |
| } |
| |
| fn f(v: u32) { |
| match v { |
| u32::$0 |
| } |
| } |
| "#, |
| expect![[r#" |
| ct MIN pub const MIN: Self |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn in_method_param() { |
| check_empty( |
| r#" |
| struct Ty(u8); |
| |
| impl Ty { |
| fn foo($0) |
| } |
| "#, |
| expect![[r#" |
| sp Self |
| st Ty |
| bn &mut self |
| bn &self |
| bn Self(…) Self($1): Self$0 |
| bn Ty(…) Ty($1): Ty$0 |
| bn mut self |
| bn self |
| kw mut |
| kw ref |
| "#]], |
| ); |
| check_empty( |
| r#" |
| struct Ty(u8); |
| |
| impl Ty { |
| fn foo(s$0) |
| } |
| "#, |
| expect![[r#" |
| sp Self |
| st Ty |
| bn &mut self |
| bn &self |
| bn Self(…) Self($1): Self$0 |
| bn Ty(…) Ty($1): Ty$0 |
| bn mut self |
| bn self |
| kw mut |
| kw ref |
| "#]], |
| ); |
| check_empty( |
| r#" |
| struct Ty(u8); |
| |
| impl Ty { |
| fn foo(s$0, foo: u8) |
| } |
| "#, |
| expect![[r#" |
| sp Self |
| st Ty |
| bn &mut self |
| bn &self |
| bn Self(…) Self($1): Self$0 |
| bn Ty(…) Ty($1): Ty$0 |
| bn mut self |
| bn self |
| kw mut |
| kw ref |
| "#]], |
| ); |
| check_empty( |
| r#" |
| struct Ty(u8); |
| |
| impl Ty { |
| fn foo(foo: u8, b$0) |
| } |
| "#, |
| expect![[r#" |
| sp Self |
| st Ty |
| bn Self(…) Self($1): Self$0 |
| bn Ty(…) Ty($1): Ty$0 |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn through_alias() { |
| check_empty( |
| r#" |
| enum Enum<T> { |
| Unit, |
| Tuple(T), |
| } |
| |
| type EnumAlias<T> = Enum<T>; |
| |
| fn f(x: EnumAlias<u8>) { |
| match x { |
| EnumAlias::$0 => (), |
| _ => (), |
| } |
| |
| } |
| |
| "#, |
| expect![[r#" |
| bn Tuple(…) Tuple($1)$0 |
| bn Unit Unit$0 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn pat_no_unstable_item_on_stable() { |
| check_empty( |
| r#" |
| //- /main.rs crate:main deps:std |
| use std::*; |
| fn foo() { |
| let a$0 |
| } |
| //- /std.rs crate:std |
| #[unstable] |
| pub struct S; |
| #[unstable] |
| pub enum Enum { |
| Variant |
| } |
| "#, |
| expect![[r#" |
| md std |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn pat_unstable_item_on_nightly() { |
| check_empty( |
| r#" |
| //- toolchain:nightly |
| //- /main.rs crate:main deps:std |
| use std::*; |
| fn foo() { |
| let a$0 |
| } |
| //- /std.rs crate:std |
| #[unstable] |
| pub struct S; |
| #[unstable] |
| pub enum Enum { |
| Variant |
| } |
| "#, |
| expect![[r#" |
| en Enum |
| md std |
| st S |
| kw mut |
| kw ref |
| "#]], |
| ); |
| } |