blob: 38e24ebc732d497aa4250f6fe23d06a2c2614f61 [file] [log] [blame]
//! Completion tests for expressions.
use expect_test::{expect, Expect};
use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
expect.assert_eq(&actual)
}
fn check_empty(ra_fixture: &str, expect: Expect) {
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual);
}
#[test]
fn complete_literal_struct_with_a_private_field() {
// `FooDesc.bar` is private, the completion should not be triggered.
check(
r#"
mod _69latrick {
pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, bar: bool }
pub fn create_foo(foo_desc: &FooDesc) -> () { () }
}
fn baz() {
use _69latrick::*;
let foo = create_foo(&$0);
}
"#,
// This should not contain `FooDesc {…}`.
expect![[r#"
ct CONST
en Enum
fn baz() fn()
fn create_foo(…) fn(&FooDesc)
fn function() fn()
ma makro!(…) macro_rules! makro
md _69latrick
md module
sc STATIC
st FooDesc
st Record
st Tuple
st Unit
un Union
ev TupleV(…) TupleV(u32)
bt u32
kw crate::
kw false
kw for
kw if
kw if let
kw loop
kw match
kw mut
kw return
kw self::
kw true
kw unsafe
kw while
kw while let
"#]],
)
}
#[test]
fn completes_various_bindings() {
check_empty(
r#"
fn func(param0 @ (param1, param2): (i32, i32)) {
let letlocal = 92;
if let ifletlocal = 100 {
match 0 {
matcharm => 1 + $0,
otherwise => (),
}
}
let letlocal2 = 44;
}
"#,
expect![[r#"
fn func(…) fn((i32, i32))
lc ifletlocal i32
lc letlocal i32
lc matcharm i32
lc param0 (i32, i32)
lc param1 i32
lc param2 i32
bt 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_all_the_things_in_fn_body() {
check(
r#"
use non_existant::Unresolved;
mod qualified { pub enum Enum { Variant } }
impl Unit {
fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) {
fn local_func() {}
$0
}
}
"#,
// `self` is in here twice, once as the module, once as the local
expect![[r#"
ct CONST
cp CONST_PARAM
en Enum
fn function() fn()
fn local_func() fn()
lc self Unit
ma makro!(…) macro_rules! makro
md module
md qualified
sp Self
sc STATIC
st Record
st Tuple
st Unit
tp TypeParam
un Union
ev TupleV(…) TupleV(u32)
bt 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
me self.foo() fn(self)
sn macro_rules
sn pd
sn ppd
?? Unresolved
"#]],
);
check(
r#"
use non_existant::Unresolved;
mod qualified { pub enum Enum { Variant } }
impl Unit {
fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) {
fn local_func() {}
self::$0
}
}
"#,
expect![[r#"
ct CONST
en Enum
fn function() fn()
ma makro!(…) macro_rules! makro
md module
md qualified
sc STATIC
st Record
st Tuple
st Unit
tt Trait
un Union
ev TupleV(…) TupleV(u32)
?? Unresolved
"#]],
);
}
#[test]
fn complete_in_block() {
check_empty(
r#"
fn foo() {
if true {
$0
}
}
"#,
expect![[r#"
fn foo() fn()
bt 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 complete_after_if_expr() {
check_empty(
r#"
fn foo() {
if true {}
$0
}
"#,
expect![[r#"
fn foo() fn()
bt u32
kw const
kw crate::
kw else
kw else if
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 complete_in_match_arm() {
check_empty(
r#"
fn foo() {
match () {
() => $0
}
}
"#,
expect![[r#"
fn foo() fn()
bt 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_in_loop_ctx() {
check_empty(
r"fn my() { loop { $0 } }",
expect![[r#"
fn my() fn()
bt u32
kw break
kw const
kw continue
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_in_let_initializer() {
check_empty(
r#"fn main() { let _ = $0 }"#,
expect![[r#"
fn main() fn()
bt 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 struct_initializer_field_expr() {
check_empty(
r#"
struct Foo {
pub f: i32,
}
fn foo() {
Foo {
f: $0
}
}
"#,
expect![[r#"
fn foo() fn()
st Foo
bt 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 shadowing_shows_single_completion() {
cov_mark::check!(shadowing_shows_single_completion);
check_empty(
r#"
fn foo() {
let bar = 92;
{
let bar = 62;
drop($0)
}
}
"#,
expect![[r#"
fn foo() fn()
lc bar i32
bt 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 in_macro_expr_frag() {
check_empty(
r#"
macro_rules! m { ($e:expr) => { $e } }
fn quux(x: i32) {
m!($0);
}
"#,
expect![[r#"
fn quux(…) fn(i32)
lc x i32
ma m!(…) macro_rules! m
bt 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
"#]],
);
check_empty(
r"
macro_rules! m { ($e:expr) => { $e } }
fn quux(x: i32) {
m!(x$0);
}
",
expect![[r#"
fn quux(…) fn(i32)
lc x i32
ma m!(…) macro_rules! m
bt 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
"#]],
);
check_empty(
r#"
macro_rules! m { ($e:expr) => { $e } }
fn quux(x: i32) {
let y = 92;
m!(x$0
}
"#,
expect![[r#""#]],
);
}
#[test]
fn enum_qualified() {
check(
r#"
impl Enum {
type AssocType = ();
const ASSOC_CONST: () = ();
fn assoc_fn() {}
}
fn func() {
Enum::$0
}
"#,
expect![[r#"
ct ASSOC_CONST const ASSOC_CONST: ()
fn assoc_fn() fn()
ta AssocType type AssocType = ()
ev RecordV {…} RecordV { field: u32 }
ev TupleV(…) TupleV(u32)
ev UnitV UnitV
"#]],
);
}
#[test]
fn ty_qualified_no_drop() {
check_empty(
r#"
//- minicore: drop
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {}
}
fn func() {
Foo::$0
}
"#,
expect![[r#""#]],
);
}
#[test]
fn with_parens() {
check_empty(
r#"
enum Enum {
Variant()
}
impl Enum {
fn variant() -> Self { Enum::Variant() }
}
fn func() {
Enum::$0()
}
"#,
expect![[r#"
fn variant fn() -> Enum
ev Variant Variant
"#]],
);
}
#[test]
fn detail_impl_trait_in_return_position() {
check_empty(
r"
//- minicore: sized
trait Trait<T> {}
fn foo<U>() -> impl Trait<U> {}
fn main() {
self::$0
}
",
expect![[r#"
fn foo() fn() -> impl Trait<U>
fn main() fn()
tt Trait
"#]],
);
}
#[test]
fn detail_async_fn() {
check_empty(
r#"
//- minicore: future, sized
trait Trait<T> {}
async fn foo() -> u8 {}
async fn bar<U>() -> impl Trait<U> {}
fn main() {
self::$0
}
"#,
expect![[r#"
fn bar() async fn() -> impl Trait<U>
fn foo() async fn() -> u8
fn main() fn()
tt Trait
"#]],
);
}
#[test]
fn detail_impl_trait_in_argument_position() {
check_empty(
r"
//- minicore: sized
trait Trait<T> {}
struct Foo;
impl Foo {
fn bar<U>(_: impl Trait<U>) {}
}
fn main() {
Foo::$0
}
",
expect![[r"
fn bar(…) fn(impl Trait<U>)
"]],
);
}
#[test]
fn complete_record_expr_path() {
check(
r#"
struct Zulu;
impl Zulu {
fn test() -> Self { }
}
fn boi(val: Zulu) { }
fn main() {
boi(Zulu:: $0 {});
}
"#,
expect![[r#"
fn test() fn() -> Zulu
"#]],
);
}
#[test]
fn return_unit_block() {
cov_mark::check!(return_unit_block);
check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#);
}
#[test]
fn return_unit_no_block() {
cov_mark::check!(return_unit_no_block);
check_edit(
"return",
r#"fn f() { match () { () => $0 } }"#,
r#"fn f() { match () { () => return } }"#,
);
}
#[test]
fn return_value_block() {
cov_mark::check!(return_value_block);
check_edit(
"return",
r#"fn f() -> i32 { if true { $0 } }"#,
r#"fn f() -> i32 { if true { return $0; } }"#,
);
}
#[test]
fn return_value_no_block() {
cov_mark::check!(return_value_no_block);
check_edit(
"return",
r#"fn f() -> i32 { match () { () => $0 } }"#,
r#"fn f() -> i32 { match () { () => return $0 } }"#,
);
}