blob: ff32eccfbff4c4aabe41d1304b453df48b922a4e [file] [log] [blame]
//! 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::
"#]],
);
}