| //! Tests that don't fit into a specific category. |
| |
| use expect_test::{expect, Expect}; |
| |
| use crate::{ |
| tests::{ |
| check_edit, completion_list, completion_list_no_kw, completion_list_with_trigger_character, |
| }, |
| CompletionItemKind, |
| }; |
| |
| use super::{do_completion_with_config, TEST_CONFIG}; |
| |
| fn check_no_kw(ra_fixture: &str, expect: Expect) { |
| let actual = completion_list_no_kw(ra_fixture); |
| expect.assert_eq(&actual) |
| } |
| |
| fn check(ra_fixture: &str, expect: Expect) { |
| let actual = completion_list(ra_fixture); |
| expect.assert_eq(&actual) |
| } |
| |
| pub(crate) fn check_with_trigger_character( |
| ra_fixture: &str, |
| trigger_character: Option<char>, |
| expect: Expect, |
| ) { |
| let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); |
| expect.assert_eq(&actual) |
| } |
| |
| #[test] |
| fn completes_if_prefix_is_keyword() { |
| check_edit( |
| "wherewolf", |
| r#" |
| fn main() { |
| let wherewolf = 92; |
| drop(where$0) |
| } |
| "#, |
| r#" |
| fn main() { |
| let wherewolf = 92; |
| drop(wherewolf) |
| } |
| "#, |
| ) |
| } |
| |
| /// Regression test for issue #6091. |
| #[test] |
| fn correctly_completes_module_items_prefixed_with_underscore() { |
| check_edit( |
| "_alpha", |
| r#" |
| fn main() { |
| _$0 |
| } |
| fn _alpha() {} |
| "#, |
| r#" |
| fn main() { |
| _alpha()$0 |
| } |
| fn _alpha() {} |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn completes_prelude() { |
| check_no_kw( |
| r#" |
| //- /main.rs edition:2018 crate:main deps:std |
| fn foo() { let x: $0 } |
| |
| //- /std/lib.rs crate:std |
| pub mod prelude { |
| pub mod rust_2018 { |
| pub struct Option; |
| } |
| } |
| "#, |
| expect![[r#" |
| md std |
| st Option Option |
| bt u32 u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_prelude_macros() { |
| check_no_kw( |
| r#" |
| //- /main.rs edition:2018 crate:main deps:std |
| fn f() {$0} |
| |
| //- /std/lib.rs crate:std |
| pub mod prelude { |
| pub mod rust_2018 { |
| pub use crate::concat; |
| } |
| } |
| |
| mod macros { |
| #[rustc_builtin_macro] |
| #[macro_export] |
| macro_rules! concat { } |
| } |
| "#, |
| expect![[r#" |
| fn f() fn() |
| ma concat!(…) macro_rules! concat |
| md std |
| bt u32 u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_std_prelude_if_core_is_defined() { |
| check_no_kw( |
| r#" |
| //- /main.rs crate:main deps:core,std |
| fn foo() { let x: $0 } |
| |
| //- /core/lib.rs crate:core |
| pub mod prelude { |
| pub mod rust_2021 { |
| pub struct Option; |
| } |
| } |
| |
| //- /std/lib.rs crate:std deps:core |
| pub mod prelude { |
| pub mod rust_2021 { |
| pub struct String; |
| } |
| } |
| "#, |
| expect![[r#" |
| md core |
| md std |
| st String String |
| bt u32 u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn respects_doc_hidden() { |
| check_no_kw( |
| r#" |
| //- /lib.rs crate:lib deps:std |
| fn f() { |
| format_$0 |
| } |
| |
| //- /std.rs crate:std |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! format_args_nl { |
| () => {} |
| } |
| |
| pub mod prelude { |
| pub mod rust_2018 {} |
| } |
| "#, |
| expect![[r#" |
| fn f() fn() |
| md std |
| bt u32 u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn respects_doc_hidden_in_assoc_item_list() { |
| check_no_kw( |
| r#" |
| //- /lib.rs crate:lib deps:std |
| struct S; |
| impl S { |
| format_$0 |
| } |
| |
| //- /std.rs crate:std |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! format_args_nl { |
| () => {} |
| } |
| |
| pub mod prelude { |
| pub mod rust_2018 {} |
| } |
| "#, |
| expect![[r#" |
| md std |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn associated_item_visibility() { |
| check_no_kw( |
| r#" |
| //- /lib.rs crate:lib new_source_root:library |
| pub struct S; |
| |
| impl S { |
| pub fn public_method() { } |
| fn private_method() { } |
| pub type PublicType = u32; |
| type PrivateType = u32; |
| pub const PUBLIC_CONST: u32 = 1; |
| const PRIVATE_CONST: u32 = 1; |
| } |
| |
| //- /main.rs crate:main deps:lib new_source_root:local |
| fn foo() { let _ = lib::S::$0 } |
| "#, |
| expect![[r#" |
| ct PUBLIC_CONST pub const PUBLIC_CONST: u32 |
| fn public_method() fn() |
| ta PublicType pub type PublicType = u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_union_associated_method() { |
| check_no_kw( |
| r#" |
| union U {}; |
| impl U { fn m() { } } |
| |
| fn foo() { let _ = U::$0 } |
| "#, |
| expect![[r#" |
| fn m() fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_trait_associated_method_1() { |
| check_no_kw( |
| r#" |
| trait Trait { fn m(); } |
| |
| fn foo() { let _ = Trait::$0 } |
| "#, |
| expect![[r#" |
| fn m() (as Trait) fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_trait_associated_method_2() { |
| check_no_kw( |
| r#" |
| trait Trait { fn m(); } |
| |
| struct S; |
| impl Trait for S {} |
| |
| fn foo() { let _ = S::$0 } |
| "#, |
| expect![[r#" |
| fn m() (as Trait) fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_trait_associated_method_3() { |
| check_no_kw( |
| r#" |
| trait Trait { fn m(); } |
| |
| struct S; |
| impl Trait for S {} |
| |
| fn foo() { let _ = <S as Trait>::$0 } |
| "#, |
| expect![[r#" |
| fn m() (as Trait) fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_ty_param_assoc_ty() { |
| check_no_kw( |
| r#" |
| trait Super { |
| type Ty; |
| const CONST: u8; |
| fn func() {} |
| fn method(&self) {} |
| } |
| |
| trait Sub: Super { |
| type SubTy; |
| const C2: (); |
| fn subfunc() {} |
| fn submethod(&self) {} |
| } |
| |
| fn foo<T: Sub>() { T::$0 } |
| "#, |
| expect![[r#" |
| ct C2 (as Sub) const C2: () |
| ct CONST (as Super) const CONST: u8 |
| fn func() (as Super) fn() |
| fn subfunc() (as Sub) fn() |
| ta SubTy (as Sub) type SubTy |
| ta Ty (as Super) type Ty |
| me method(…) (as Super) fn(&self) |
| me submethod(…) (as Sub) fn(&self) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_self_param_assoc_ty() { |
| check_no_kw( |
| r#" |
| trait Super { |
| type Ty; |
| const CONST: u8 = 0; |
| fn func() {} |
| fn method(&self) {} |
| } |
| |
| trait Sub: Super { |
| type SubTy; |
| const C2: () = (); |
| fn subfunc() {} |
| fn submethod(&self) {} |
| } |
| |
| struct Wrap<T>(T); |
| impl<T> Super for Wrap<T> {} |
| impl<T> Sub for Wrap<T> { |
| fn subfunc() { |
| // Should be able to assume `Self: Sub + Super` |
| Self::$0 |
| } |
| } |
| "#, |
| expect![[r#" |
| ct C2 (as Sub) const C2: () |
| ct CONST (as Super) const CONST: u8 |
| fn func() (as Super) fn() |
| fn subfunc() (as Sub) fn() |
| ta SubTy (as Sub) type SubTy |
| ta Ty (as Super) type Ty |
| me method(…) (as Super) fn(&self) |
| me submethod(…) (as Sub) fn(&self) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_type_alias() { |
| check_no_kw( |
| r#" |
| struct S; |
| impl S { fn foo() {} } |
| type T = S; |
| impl T { fn bar() {} } |
| |
| fn main() { T::$0; } |
| "#, |
| expect![[r#" |
| fn bar() fn() |
| fn foo() fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_qualified_macros() { |
| check_no_kw( |
| r#" |
| #[macro_export] |
| macro_rules! foo { () => {} } |
| |
| fn main() { let _ = crate::$0 } |
| "#, |
| expect![[r#" |
| fn main() fn() |
| ma foo!(…) macro_rules! foo |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn does_not_complete_non_fn_macros() { |
| check_no_kw( |
| r#" |
| mod m { |
| #[rustc_builtin_macro] |
| pub macro Clone {} |
| } |
| |
| fn f() {m::$0} |
| "#, |
| expect![[r#""#]], |
| ); |
| check_no_kw( |
| r#" |
| mod m { |
| #[rustc_builtin_macro] |
| pub macro bench {} |
| } |
| |
| fn f() {m::$0} |
| "#, |
| expect![[r#""#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_reexported_items_under_correct_name() { |
| check_no_kw( |
| r#" |
| fn foo() { self::m::$0 } |
| |
| mod m { |
| pub use super::p::wrong_fn as right_fn; |
| pub use super::p::WRONG_CONST as RIGHT_CONST; |
| pub use super::p::WrongType as RightType; |
| } |
| mod p { |
| pub fn wrong_fn() {} |
| pub const WRONG_CONST: u32 = 1; |
| pub struct WrongType {}; |
| } |
| "#, |
| expect![[r#" |
| ct RIGHT_CONST u32 |
| fn right_fn() fn() |
| st RightType WrongType |
| "#]], |
| ); |
| |
| check_edit( |
| "RightType", |
| r#" |
| fn foo() { self::m::$0 } |
| |
| mod m { |
| pub use super::p::wrong_fn as right_fn; |
| pub use super::p::WRONG_CONST as RIGHT_CONST; |
| pub use super::p::WrongType as RightType; |
| } |
| mod p { |
| pub fn wrong_fn() {} |
| pub const WRONG_CONST: u32 = 1; |
| pub struct WrongType {}; |
| } |
| "#, |
| r#" |
| fn foo() { self::m::RightType } |
| |
| mod m { |
| pub use super::p::wrong_fn as right_fn; |
| pub use super::p::WRONG_CONST as RIGHT_CONST; |
| pub use super::p::WrongType as RightType; |
| } |
| mod p { |
| pub fn wrong_fn() {} |
| pub const WRONG_CONST: u32 = 1; |
| pub struct WrongType {}; |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn completes_in_simple_macro_call() { |
| check_no_kw( |
| r#" |
| macro_rules! m { ($e:expr) => { $e } } |
| fn main() { m!(self::f$0); } |
| fn foo() {} |
| "#, |
| expect![[r#" |
| fn foo() fn() |
| fn main() fn() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn function_mod_share_name() { |
| check_no_kw( |
| r#" |
| fn foo() { self::m::$0 } |
| |
| mod m { |
| pub mod z {} |
| pub fn z() {} |
| } |
| "#, |
| expect![[r#" |
| fn z() fn() |
| md z |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_hashmap_new() { |
| check_no_kw( |
| r#" |
| struct RandomState; |
| struct HashMap<K, V, S = RandomState> {} |
| |
| impl<K, V> HashMap<K, V, RandomState> { |
| pub fn new() -> HashMap<K, V, RandomState> { } |
| } |
| fn foo() { |
| HashMap::$0 |
| } |
| "#, |
| expect![[r#" |
| fn new() fn() -> HashMap<K, V, RandomState> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_variant_through_self() { |
| cov_mark::check!(completes_variant_through_self); |
| check_no_kw( |
| r#" |
| enum Foo { |
| Bar, |
| Baz, |
| } |
| |
| impl Foo { |
| fn foo(self) { |
| Self::$0 |
| } |
| } |
| "#, |
| expect![[r#" |
| ev Bar Bar |
| ev Baz Baz |
| me foo(…) fn(self) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_non_exhaustive_variant_within_the_defining_crate() { |
| check_no_kw( |
| r#" |
| enum Foo { |
| #[non_exhaustive] |
| Bar, |
| Baz, |
| } |
| |
| fn foo(self) { |
| Foo::$0 |
| } |
| "#, |
| expect![[r#" |
| ev Bar Bar |
| ev Baz Baz |
| "#]], |
| ); |
| |
| check_no_kw( |
| r#" |
| //- /main.rs crate:main deps:e |
| fn foo(self) { |
| e::Foo::$0 |
| } |
| |
| //- /e.rs crate:e |
| enum Foo { |
| #[non_exhaustive] |
| Bar, |
| Baz, |
| } |
| "#, |
| expect![[r#" |
| ev Baz Baz |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_primitive_assoc_const() { |
| cov_mark::check!(completes_primitive_assoc_const); |
| check_no_kw( |
| r#" |
| //- /lib.rs crate:lib deps:core |
| fn f() { |
| u8::$0 |
| } |
| |
| //- /core.rs crate:core |
| #![rustc_coherence_is_core] |
| #[lang = "u8"] |
| impl u8 { |
| pub const MAX: Self = 255; |
| |
| pub fn func(self) {} |
| } |
| "#, |
| expect![[r#" |
| ct MAX pub const MAX: Self |
| me func(…) fn(self) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_variant_through_alias() { |
| cov_mark::check!(completes_variant_through_alias); |
| check_no_kw( |
| r#" |
| enum Foo { |
| Bar |
| } |
| type Foo2 = Foo; |
| fn main() { |
| Foo2::$0 |
| } |
| "#, |
| expect![[r#" |
| ev Bar Bar |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn respects_doc_hidden2() { |
| check_no_kw( |
| r#" |
| //- /lib.rs crate:lib deps:dep |
| fn f() { |
| dep::$0 |
| } |
| |
| //- /dep.rs crate:dep |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! m { |
| () => {} |
| } |
| |
| #[doc(hidden)] |
| pub fn f() {} |
| |
| #[doc(hidden)] |
| pub struct S; |
| |
| #[doc(hidden)] |
| pub mod m {} |
| "#, |
| expect![[r#""#]], |
| ) |
| } |
| |
| #[test] |
| fn type_anchor_empty() { |
| check_no_kw( |
| r#" |
| trait Foo { |
| fn foo() -> Self; |
| } |
| struct Bar; |
| impl Foo for Bar { |
| fn foo() -> { |
| Bar |
| } |
| } |
| fn bar() -> Bar { |
| <_>::$0 |
| } |
| "#, |
| expect![[r#" |
| fn foo() (as Foo) fn() -> Self |
| ex Bar |
| ex bar() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn type_anchor_type() { |
| check_no_kw( |
| r#" |
| trait Foo { |
| fn foo() -> Self; |
| } |
| struct Bar; |
| impl Bar { |
| fn bar() {} |
| } |
| impl Foo for Bar { |
| fn foo() -> { |
| Bar |
| } |
| } |
| fn bar() -> Bar { |
| <Bar>::$0 |
| } |
| "#, |
| expect![[r#" |
| fn bar() fn() |
| fn foo() (as Foo) fn() -> Self |
| ex Bar |
| ex bar() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn type_anchor_type_trait() { |
| check_no_kw( |
| r#" |
| trait Foo { |
| fn foo() -> Self; |
| } |
| struct Bar; |
| impl Bar { |
| fn bar() {} |
| } |
| impl Foo for Bar { |
| fn foo() -> { |
| Bar |
| } |
| } |
| fn bar() -> Bar { |
| <Bar as Foo>::$0 |
| } |
| "#, |
| expect![[r#" |
| fn foo() (as Foo) fn() -> Self |
| ex Bar |
| ex bar() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_fn_in_pub_trait_generated_by_macro() { |
| check_no_kw( |
| r#" |
| mod other_mod { |
| macro_rules! make_method { |
| ($name:ident) => { |
| fn $name(&self) {} |
| }; |
| } |
| |
| pub trait MyTrait { |
| make_method! { by_macro } |
| fn not_by_macro(&self) {} |
| } |
| |
| pub struct Foo {} |
| |
| impl MyTrait for Foo {} |
| } |
| |
| fn main() { |
| use other_mod::{Foo, MyTrait}; |
| let f = Foo {}; |
| f.$0 |
| } |
| "#, |
| expect![[r#" |
| me by_macro() (as MyTrait) fn(&self) |
| me not_by_macro() (as MyTrait) fn(&self) |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_fn_in_pub_trait_generated_by_recursive_macro() { |
| check_no_kw( |
| r#" |
| mod other_mod { |
| macro_rules! make_method { |
| ($name:ident) => { |
| fn $name(&self) {} |
| }; |
| } |
| |
| macro_rules! make_trait { |
| () => { |
| pub trait MyTrait { |
| make_method! { by_macro } |
| fn not_by_macro(&self) {} |
| } |
| } |
| } |
| |
| make_trait!(); |
| |
| pub struct Foo {} |
| |
| impl MyTrait for Foo {} |
| } |
| |
| fn main() { |
| use other_mod::{Foo, MyTrait}; |
| let f = Foo {}; |
| f.$0 |
| } |
| "#, |
| expect![[r#" |
| me by_macro() (as MyTrait) fn(&self) |
| me not_by_macro() (as MyTrait) fn(&self) |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_const_in_pub_trait_generated_by_macro() { |
| check_no_kw( |
| r#" |
| mod other_mod { |
| macro_rules! make_const { |
| ($name:ident) => { |
| const $name: u8 = 1; |
| }; |
| } |
| |
| pub trait MyTrait { |
| make_const! { by_macro } |
| } |
| |
| pub struct Foo {} |
| |
| impl MyTrait for Foo {} |
| } |
| |
| fn main() { |
| use other_mod::{Foo, MyTrait}; |
| let f = Foo {}; |
| Foo::$0 |
| } |
| "#, |
| expect![[r#" |
| ct by_macro (as MyTrait) pub const by_macro: u8 |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn completes_locals_from_macros() { |
| check_no_kw( |
| r#" |
| |
| macro_rules! x { |
| ($x:ident, $expr:expr) => { |
| let $x = 0; |
| $expr |
| }; |
| } |
| fn main() { |
| x! { |
| foobar, { |
| f$0 |
| } |
| }; |
| } |
| "#, |
| expect![[r#" |
| fn main() fn() |
| lc foobar i32 |
| ma x!(…) macro_rules! x |
| bt u32 u32 |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn regression_12644() { |
| check_no_kw( |
| r#" |
| macro_rules! __rust_force_expr { |
| ($e:expr) => { |
| $e |
| }; |
| } |
| macro_rules! vec { |
| ($elem:expr) => { |
| __rust_force_expr!($elem) |
| }; |
| } |
| |
| struct Struct; |
| impl Struct { |
| fn foo(self) {} |
| } |
| |
| fn f() { |
| vec![Struct].$0; |
| } |
| "#, |
| expect![[r#" |
| me foo() fn(self) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_after_colon_with_trigger() { |
| check_with_trigger_character( |
| r#" |
| //- minicore: option |
| fn foo { ::$0 } |
| "#, |
| Some(':'), |
| expect![[r#" |
| md core |
| "#]], |
| ); |
| check_with_trigger_character( |
| r#" |
| //- minicore: option |
| fn foo { /* test */::$0 } |
| "#, |
| Some(':'), |
| expect![[r#" |
| md core |
| "#]], |
| ); |
| |
| check_with_trigger_character( |
| r#" |
| fn foo { crate::$0 } |
| "#, |
| Some(':'), |
| expect![[r#" |
| fn foo() fn() |
| "#]], |
| ); |
| |
| check_with_trigger_character( |
| r#" |
| fn foo { crate:$0 } |
| "#, |
| Some(':'), |
| expect![""], |
| ); |
| } |
| |
| #[test] |
| fn completes_after_colon_without_trigger() { |
| check_with_trigger_character( |
| r#" |
| fn foo { crate::$0 } |
| "#, |
| None, |
| expect![[r#" |
| fn foo() fn() |
| "#]], |
| ); |
| |
| check_with_trigger_character( |
| r#" |
| fn foo { crate:$0 } |
| "#, |
| None, |
| expect![""], |
| ); |
| } |
| |
| #[test] |
| fn no_completions_in_invalid_path() { |
| check( |
| r#" |
| fn foo { crate:::$0 } |
| "#, |
| expect![""], |
| ); |
| check_no_kw( |
| r#" |
| fn foo { crate::::$0 } |
| "#, |
| expect![""], |
| ) |
| } |
| |
| #[test] |
| fn completes_struct_via_doc_alias_in_fn_body() { |
| check( |
| r#" |
| #[doc(alias = "Bar")] |
| struct Foo; |
| |
| fn here_we_go() { |
| $0 |
| } |
| "#, |
| expect![[r#" |
| fn here_we_go() fn() |
| st Foo (alias Bar) Foo |
| bt u32 u32 |
| kw const |
| kw crate:: |
| kw enum |
| kw extern |
| kw false |
| kw fn |
| kw for |
| kw if |
| kw if let |
| kw impl |
| kw let |
| kw loop |
| kw match |
| kw mod |
| kw return |
| kw self:: |
| kw static |
| kw struct |
| kw trait |
| kw true |
| kw type |
| kw union |
| kw unsafe |
| kw use |
| kw while |
| kw while let |
| sn macro_rules |
| sn pd |
| sn ppd |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_struct_via_multiple_doc_aliases_in_fn_body() { |
| check( |
| r#" |
| #[doc(alias("Bar", "Qux"))] |
| #[doc(alias = "Baz")] |
| struct Foo; |
| |
| fn here_we_go() { |
| B$0 |
| } |
| "#, |
| expect![[r#" |
| fn here_we_go() fn() |
| st Foo (alias Bar, Qux, Baz) Foo |
| bt u32 u32 |
| kw const |
| kw crate:: |
| kw enum |
| kw extern |
| kw false |
| kw fn |
| kw for |
| kw if |
| kw if let |
| kw impl |
| kw let |
| kw loop |
| kw match |
| kw mod |
| kw return |
| kw self:: |
| kw static |
| kw struct |
| kw trait |
| kw true |
| kw type |
| kw union |
| kw unsafe |
| kw use |
| kw while |
| kw while let |
| sn macro_rules |
| sn pd |
| sn ppd |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_field_name_via_doc_alias_in_fn_body() { |
| check( |
| r#" |
| struct Foo { |
| #[doc(alias = "qux")] |
| bar: u8 |
| }; |
| |
| fn here_we_go() { |
| let foo = Foo { q$0 } |
| } |
| "#, |
| expect![[r#" |
| fd bar (alias qux) u8 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_struct_fn_name_via_doc_alias_in_fn_body() { |
| check( |
| r#" |
| struct Foo; |
| impl Foo { |
| #[doc(alias = "qux")] |
| fn bar() -> u8 { 1 } |
| } |
| |
| fn here_we_go() { |
| Foo::q$0 |
| } |
| "#, |
| expect![[r#" |
| fn bar() (alias qux) fn() -> u8 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_method_name_via_doc_alias_in_fn_body() { |
| check( |
| r#" |
| struct Foo { |
| bar: u8 |
| } |
| impl Foo { |
| #[doc(alias = "qux")] |
| fn baz(&self) -> u8 { |
| self.bar |
| } |
| } |
| |
| fn here_we_go() { |
| let foo = Foo { field: 42 }; |
| foo.q$0 |
| } |
| "#, |
| expect![[r#" |
| fd bar u8 |
| me baz() (alias qux) fn(&self) -> u8 |
| sn box Box::new(expr) |
| sn call function(expr) |
| sn dbg dbg!(expr) |
| sn dbgr dbg!(&expr) |
| sn deref *expr |
| sn let let |
| sn letm let mut |
| sn match match expr {} |
| sn ref &expr |
| sn refm &mut expr |
| sn return return expr |
| sn unsafe unsafe {} |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_fn_name_via_doc_alias_in_fn_body() { |
| check( |
| r#" |
| #[doc(alias = "qux")] |
| fn foo() {} |
| fn bar() { qu$0 } |
| "#, |
| expect![[r#" |
| fn bar() fn() |
| fn foo() (alias qux) fn() |
| bt u32 u32 |
| kw const |
| kw crate:: |
| kw enum |
| kw extern |
| kw false |
| kw fn |
| kw for |
| kw if |
| kw if let |
| kw impl |
| kw let |
| kw loop |
| kw match |
| kw mod |
| kw return |
| kw self:: |
| kw static |
| kw struct |
| kw trait |
| kw true |
| kw type |
| kw union |
| kw unsafe |
| kw use |
| kw while |
| kw while let |
| sn macro_rules |
| sn pd |
| sn ppd |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_struct_name_via_doc_alias_in_another_mod() { |
| check( |
| r#" |
| mod foo { |
| #[doc(alias = "Qux")] |
| pub struct Bar(u8); |
| } |
| |
| fn here_we_go() { |
| use foo; |
| let foo = foo::Q$0 |
| } |
| "#, |
| expect![[r#" |
| st Bar (alias Qux) Bar |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_use_via_doc_alias_in_another_mod() { |
| check( |
| r#" |
| mod foo { |
| #[doc(alias = "Qux")] |
| pub struct Bar(u8); |
| } |
| |
| fn here_we_go() { |
| use foo::Q$0; |
| } |
| "#, |
| expect![[r#" |
| st Bar (alias Qux) Bar |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_flyimport_with_doc_alias_in_another_mod() { |
| check( |
| r#" |
| mod foo { |
| #[doc(alias = "Qux")] |
| pub struct Bar(); |
| } |
| |
| fn here_we_go() { |
| let foo = Bar$0 |
| } |
| "#, |
| expect![[r#" |
| fn here_we_go() fn() |
| md foo |
| st Bar (alias Qux) (use foo::Bar) Bar |
| bt u32 u32 |
| kw crate:: |
| kw false |
| kw for |
| kw if |
| kw if let |
| kw loop |
| kw match |
| kw return |
| kw self:: |
| kw true |
| kw unsafe |
| kw while |
| kw while let |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn completes_only_public() { |
| check( |
| r#" |
| //- /e.rs |
| pub(self) fn i_should_be_hidden() {} |
| pub(in crate::e) fn i_should_also_be_hidden() {} |
| pub fn i_am_public () {} |
| |
| //- /lib.rs crate:krate |
| pub mod e; |
| |
| //- /main.rs deps:krate crate:main |
| use krate::e; |
| fn main() { |
| e::$0 |
| }"#, |
| expect![ |
| "fn i_am_public() fn() |
| " |
| ], |
| ) |
| } |
| |
| #[test] |
| fn completion_filtering_excludes_non_identifier_doc_aliases() { |
| check_edit( |
| "PartialOrdcmporder", |
| r#" |
| #[doc(alias = ">")] |
| #[doc(alias = "cmp")] |
| #[doc(alias = "order")] |
| trait PartialOrd {} |
| |
| struct Foo<T: Partial$0 |
| "#, |
| r#" |
| #[doc(alias = ">")] |
| #[doc(alias = "cmp")] |
| #[doc(alias = "order")] |
| trait PartialOrd {} |
| |
| struct Foo<T: PartialOrd |
| "#, |
| ); |
| } |
| |
| fn check_signatures(src: &str, kind: CompletionItemKind, reduced: Expect, full: Expect) { |
| const FULL_SIGNATURES_CONFIG: crate::CompletionConfig = { |
| let mut x = TEST_CONFIG; |
| x.full_function_signatures = true; |
| x |
| }; |
| |
| // reduced signature |
| let completion = do_completion_with_config(TEST_CONFIG, src, kind); |
| assert!(completion[0].detail.is_some()); |
| reduced.assert_eq(completion[0].detail.as_ref().unwrap()); |
| |
| // full signature |
| let completion = do_completion_with_config(FULL_SIGNATURES_CONFIG, src, kind); |
| assert!(completion[0].detail.is_some()); |
| full.assert_eq(completion[0].detail.as_ref().unwrap()); |
| } |
| |
| #[test] |
| fn respects_full_function_signatures() { |
| check_signatures( |
| r#" |
| pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone, { 0u8 } |
| fn main() { fo$0 } |
| "#, |
| CompletionItemKind::SymbolKind(ide_db::SymbolKind::Function), |
| expect!("fn(&mut T) -> u8"), |
| expect!("pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone,"), |
| ); |
| |
| check_signatures( |
| r#" |
| struct Foo; |
| struct Bar; |
| impl Bar { |
| pub const fn baz(x: Foo) -> ! { loop {} }; |
| } |
| |
| fn main() { Bar::b$0 } |
| "#, |
| CompletionItemKind::SymbolKind(ide_db::SymbolKind::Function), |
| expect!("const fn(Foo) -> !"), |
| expect!("pub const fn baz(x: Foo) -> !"), |
| ); |
| |
| check_signatures( |
| r#" |
| struct Foo; |
| struct Bar; |
| impl Bar { |
| pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> ! { loop {} }; |
| } |
| |
| fn main() { |
| let mut bar = Bar; |
| bar.b$0 |
| } |
| "#, |
| CompletionItemKind::Method, |
| expect!("const fn(&'foo mut self, &Foo) -> !"), |
| expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"), |
| ); |
| } |
| |
| #[test] |
| fn skips_underscore() { |
| check_with_trigger_character( |
| r#" |
| fn foo(_$0) { } |
| "#, |
| Some('_'), |
| expect![[r#""#]], |
| ); |
| check_with_trigger_character( |
| r#" |
| fn foo(_: _$0) { } |
| "#, |
| Some('_'), |
| expect![[r#""#]], |
| ); |
| check_with_trigger_character( |
| r#" |
| fn foo<T>() { |
| foo::<_$0>(); |
| } |
| "#, |
| Some('_'), |
| expect![[r#""#]], |
| ); |
| // underscore expressions are fine, they are invalid so the user definitely meant to type an |
| // underscored name here |
| check_with_trigger_character( |
| r#" |
| fn foo() { |
| _$0 |
| } |
| "#, |
| Some('_'), |
| expect![[r#" |
| fn foo() fn() |
| bt u32 u32 |
| kw const |
| kw crate:: |
| kw enum |
| kw extern |
| kw false |
| kw fn |
| kw for |
| kw if |
| kw if let |
| kw impl |
| kw let |
| kw loop |
| kw match |
| kw mod |
| kw return |
| kw self:: |
| kw static |
| kw struct |
| kw trait |
| kw true |
| kw type |
| kw union |
| kw unsafe |
| kw use |
| kw while |
| kw while let |
| sn macro_rules |
| sn pd |
| sn ppd |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn no_skip_underscore_ident() { |
| check_with_trigger_character( |
| r#" |
| fn foo(a_$0) { } |
| "#, |
| Some('_'), |
| expect![[r#" |
| kw mut |
| kw ref |
| "#]], |
| ); |
| check_with_trigger_character( |
| r#" |
| fn foo(_: a_$0) { } |
| "#, |
| Some('_'), |
| expect![[r#" |
| bt u32 u32 |
| kw crate:: |
| kw self:: |
| "#]], |
| ); |
| check_with_trigger_character( |
| r#" |
| fn foo<T>() { |
| foo::<a_$0>(); |
| } |
| "#, |
| Some('_'), |
| expect![[r#" |
| tp T |
| bt u32 u32 |
| kw crate:: |
| kw self:: |
| "#]], |
| ); |
| } |