blob: a653314233d39edc55ed72e2c937e3b5fcb028f9 [file] [log] [blame]
//! Completion tests for expressions.
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}{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 Unit
en Enum Enum
fn baz() fn()
fn create_foo(…) fn(&FooDesc)
fn function() fn()
ma makro!(…) macro_rules! makro
md _69latrick
md module
sc STATIC Unit
st FooDesc FooDesc
st Record Record
st Tuple Tuple
st Unit Unit
un Union Union
ev TupleV(…) TupleV(u32)
bt u32 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 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
ex ifletlocal
ex letlocal
ex matcharm
ex param1
ex param2
"#]],
);
}
#[test]
fn completes_all_the_things_in_fn_body() {
check(
r#"
use non_existent::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 Unit
cp CONST_PARAM
en Enum Enum
fn function() fn()
fn local_func() fn()
me self.foo() fn(self)
lc self Unit
ma makro!(…) macro_rules! makro
md module
md qualified
sp Self Unit
sc STATIC Unit
st Record Record
st Tuple Tuple
st Unit Unit
tp TypeParam
un Union Union
ev TupleV(…) TupleV(u32)
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
?? Unresolved
"#]],
);
check(
r#"
use non_existent::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 Unit
en Enum Enum
fn function() fn()
ma makro!(…) macro_rules! makro
md module
md qualified
sc STATIC Unit
st Record Record
st Tuple Tuple
st Unit Unit
tt Trait
un Union 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 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
ex false
ex true
"#]],
)
}
#[test]
fn complete_after_if_expr() {
check_empty(
r#"
fn foo() {
if true {}
$0
}
"#,
expect![[r#"
fn foo() fn()
bt u32 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 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 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
"#]],
);
check_empty(
r"fn my() { loop { foo.$0 } }",
expect![[r#"
sn box Box::new(expr)
sn break break expr
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn if if expr {}
sn let let
sn letm let mut
sn match match expr {}
sn not !expr
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
sn while while expr {}
"#]],
);
}
#[test]
fn completes_in_let_initializer() {
check_empty(
r#"fn main() { let _ = $0 }"#,
expect![[r#"
fn main() fn()
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 struct_initializer_field_expr() {
check_empty(
r#"
struct Foo {
pub f: i32,
}
fn foo() {
Foo {
f: $0
}
}
"#,
expect![[r#"
fn foo() fn()
st Foo Foo
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 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 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 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 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#"
fn quux(…) fn(i32)
lc x i32
lc y i32
ma m!(…) macro_rules! m
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 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
ex Zulu
ex Zulu::test()
"#]],
);
}
#[test]
fn variant_with_struct() {
check_empty(
r#"
pub struct YoloVariant {
pub f: usize
}
pub enum HH {
Yolo(YoloVariant),
}
fn brr() {
let t = HH::Yolo(Y$0);
}
"#,
expect![[r#"
en HH HH
fn brr() fn()
st YoloVariant YoloVariant
st YoloVariant {…} YoloVariant { f: usize }
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 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 } }"#,
);
}
#[test]
fn else_completion_after_if() {
check_empty(
r#"
fn foo() { if foo {} $0 }
"#,
expect![[r#"
fn foo() fn()
bt u32 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
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 }
"#,
expect![[r#"
fn foo() fn()
bt u32 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
"#]],
);
check_empty(
r#"
fn foo() { bar(if foo {} $0) }
"#,
expect![[r#"
fn foo() fn()
bt u32 u32
kw crate::
kw else
kw else if
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#"
fn foo() { bar(if foo {} el$0) }
"#,
expect![[r#"
fn foo() fn()
bt u32 u32
kw crate::
kw else
kw else if
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#"
fn foo() { if foo {} $0 let x = 92; }
"#,
expect![[r#"
fn foo() fn()
bt u32 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
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 let x = 92; }
"#,
expect![[r#"
fn foo() fn()
bt u32 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
"#]],
);
check_empty(
r#"
fn foo() { if foo {} el$0 { let x = 92; } }
"#,
expect![[r#"
fn foo() fn()
bt u32 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 expr_no_unstable_item_on_stable() {
check_empty(
r#"
//- /main.rs crate:main deps:std
use std::*;
fn main() {
$0
}
//- /std.rs crate:std
#[unstable]
pub struct UnstableThisShouldNotBeListed;
"#,
expect![[r#"
fn main() fn()
md std
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 expr_unstable_item_on_nightly() {
check_empty(
r#"
//- toolchain:nightly
//- /main.rs crate:main deps:std
use std::*;
fn main() {
$0
}
//- /std.rs crate:std
#[unstable]
pub struct UnstableButWeAreOnNightlyAnyway;
"#,
expect![[r#"
fn main() fn()
md std
st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
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 inside_format_args_completions_work() {
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("{}", Foo.$0);
}
"#,
expect![[r#"
me foo() fn(&self)
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn match match expr {}
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
"#]],
);
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("{}", Foo.f$0);
}
"#,
expect![[r#"
me foo() fn(&self)
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn match match expr {}
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
"#]],
);
}
#[test]
fn inside_faulty_format_args_completions_work() {
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("", Foo.$0);
}
"#,
expect![[r#"
me foo() fn(&self)
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn match match expr {}
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
"#]],
);
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("", Foo.f$0);
}
"#,
expect![[r#"
me foo() fn(&self)
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn match match expr {}
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
"#]],
);
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("{} {named} {captured} {named} {}", a, named = c, Foo.f$0);
}
"#,
expect![[r#"
me foo() fn(&self)
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn match match expr {}
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
"#]],
);
check_empty(
r#"
//- minicore: fmt
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
format_args!("{", Foo.f$0);
}
"#,
expect![[r#"
sn box Box::new(expr)
sn call function(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn deref *expr
sn if if expr {}
sn match match expr {}
sn not !expr
sn ref &expr
sn refm &mut expr
sn return return expr
sn unsafe unsafe {}
sn while while expr {}
"#]],
);
}