2021-07-23 16:37:19 +02:00
|
|
|
//! Completion tests for expressions.
|
|
|
|
|
use expect_test::{expect, Expect};
|
|
|
|
|
|
|
|
|
|
use crate::tests::{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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-04 00:46:50 +02:00
|
|
|
#[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##"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw mut
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
st FooDesc
|
|
|
|
|
fn create_foo(…) fn(&FooDesc)
|
|
|
|
|
bt u32
|
|
|
|
|
tt Trait
|
|
|
|
|
en Enum
|
|
|
|
|
st Record
|
|
|
|
|
st Tuple
|
|
|
|
|
md module
|
|
|
|
|
fn baz() fn()
|
|
|
|
|
st Unit
|
|
|
|
|
md _69latrick
|
|
|
|
|
ma makro!(…) #[macro_export] macro_rules! makro
|
|
|
|
|
fn function() fn()
|
|
|
|
|
sc STATIC
|
|
|
|
|
un Union
|
|
|
|
|
ev TupleV(…) (u32)
|
|
|
|
|
ct CONST
|
|
|
|
|
"##]],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 16:37:19 +02:00
|
|
|
#[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#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
lc matcharm i32
|
|
|
|
|
lc ifletlocal i32
|
|
|
|
|
lc letlocal i32
|
|
|
|
|
lc param0 (i32, i32)
|
|
|
|
|
lc param1 i32
|
|
|
|
|
lc param2 i32
|
|
|
|
|
fn func(…) fn((i32, i32))
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-10-27 16:24:42 +02:00
|
|
|
fn completes_all_the_things_in_fn_body() {
|
2021-07-23 16:37:19 +02:00
|
|
|
cov_mark::check!(unqualified_skip_lifetime_completion);
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#,
|
2021-07-23 17:02:39 +02:00
|
|
|
// `self` is in here twice, once as the module, once as the local
|
2021-07-23 16:37:19 +02:00
|
|
|
expect![[r##"
|
2022-02-03 16:05:21 +01:00
|
|
|
me self.foo() fn(self)
|
2021-07-23 16:37:19 +02:00
|
|
|
kw unsafe
|
|
|
|
|
kw fn
|
|
|
|
|
kw const
|
|
|
|
|
kw type
|
|
|
|
|
kw impl
|
|
|
|
|
kw extern
|
|
|
|
|
kw use
|
|
|
|
|
kw trait
|
|
|
|
|
kw static
|
|
|
|
|
kw mod
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw let
|
|
|
|
|
kw return
|
|
|
|
|
sn pd
|
|
|
|
|
sn ppd
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn local_func() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
lc self Unit
|
|
|
|
|
tp TypeParam
|
|
|
|
|
cp CONST_PARAM
|
|
|
|
|
sp Self
|
|
|
|
|
tt Trait
|
|
|
|
|
en Enum
|
|
|
|
|
st Record
|
|
|
|
|
st Tuple
|
|
|
|
|
md module
|
|
|
|
|
st Unit
|
|
|
|
|
md qualified
|
|
|
|
|
ma makro!(…) #[macro_export] macro_rules! makro
|
|
|
|
|
?? Unresolved
|
|
|
|
|
fn function() fn()
|
|
|
|
|
sc STATIC
|
2021-07-23 17:02:39 +02:00
|
|
|
un Union
|
2021-07-23 16:37:19 +02:00
|
|
|
ev TupleV(…) (u32)
|
|
|
|
|
ct CONST
|
|
|
|
|
"##]],
|
|
|
|
|
);
|
2021-07-23 17:02:39 +02:00
|
|
|
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##"
|
|
|
|
|
tt Trait
|
|
|
|
|
en Enum
|
|
|
|
|
st Record
|
|
|
|
|
st Tuple
|
|
|
|
|
md module
|
|
|
|
|
st Unit
|
|
|
|
|
md qualified
|
|
|
|
|
ma makro!(…) #[macro_export] macro_rules! makro
|
|
|
|
|
?? Unresolved
|
|
|
|
|
fn function() fn()
|
|
|
|
|
sc STATIC
|
|
|
|
|
un Union
|
|
|
|
|
ev TupleV(…) (u32)
|
|
|
|
|
ct CONST
|
|
|
|
|
"##]],
|
|
|
|
|
);
|
2021-07-23 16:37:19 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-27 16:24:42 +02:00
|
|
|
#[test]
|
|
|
|
|
fn complete_in_block() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
fn foo() {
|
|
|
|
|
if true {
|
|
|
|
|
$0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw fn
|
|
|
|
|
kw const
|
|
|
|
|
kw type
|
|
|
|
|
kw impl
|
|
|
|
|
kw extern
|
|
|
|
|
kw use
|
|
|
|
|
kw trait
|
|
|
|
|
kw static
|
|
|
|
|
kw mod
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw let
|
|
|
|
|
kw return
|
|
|
|
|
sn pd
|
|
|
|
|
sn ppd
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn foo() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn complete_after_if_expr() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
fn foo() {
|
|
|
|
|
if true {}
|
|
|
|
|
$0
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw fn
|
|
|
|
|
kw const
|
|
|
|
|
kw type
|
|
|
|
|
kw impl
|
|
|
|
|
kw extern
|
|
|
|
|
kw use
|
|
|
|
|
kw trait
|
|
|
|
|
kw static
|
|
|
|
|
kw mod
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw let
|
|
|
|
|
kw else
|
|
|
|
|
kw else if
|
|
|
|
|
kw return
|
|
|
|
|
sn pd
|
|
|
|
|
sn ppd
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn foo() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn complete_in_match_arm() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
fn foo() {
|
|
|
|
|
match () {
|
|
|
|
|
() => $0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn foo() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn completes_in_loop_ctx() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r"fn my() { loop { $0 } }",
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw fn
|
|
|
|
|
kw const
|
|
|
|
|
kw type
|
|
|
|
|
kw impl
|
|
|
|
|
kw extern
|
|
|
|
|
kw use
|
|
|
|
|
kw trait
|
|
|
|
|
kw static
|
|
|
|
|
kw mod
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw let
|
|
|
|
|
kw continue
|
|
|
|
|
kw break
|
|
|
|
|
kw return
|
|
|
|
|
sn pd
|
|
|
|
|
sn ppd
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn my() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn completes_in_let_initializer() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"fn main() { let _ = $0 }"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
fn main() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn struct_initializer_field_expr() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
struct Foo {
|
|
|
|
|
pub f: i32,
|
|
|
|
|
}
|
|
|
|
|
fn foo() {
|
|
|
|
|
Foo {
|
|
|
|
|
f: $0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
st Foo
|
|
|
|
|
fn foo() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 16:37:19 +02:00
|
|
|
#[test]
|
|
|
|
|
fn shadowing_shows_single_completion() {
|
2021-08-03 17:36:06 +03:00
|
|
|
cov_mark::check!(shadowing_shows_single_completion);
|
|
|
|
|
|
2021-07-23 16:37:19 +02:00
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
fn foo() {
|
|
|
|
|
let bar = 92;
|
|
|
|
|
{
|
|
|
|
|
let bar = 62;
|
|
|
|
|
drop($0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
lc bar i32
|
|
|
|
|
fn foo() fn()
|
|
|
|
|
bt u32
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn in_macro_expr_frag() {
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
|
fn quux(x: i32) {
|
|
|
|
|
m!($0);
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
bt u32
|
|
|
|
|
lc x i32
|
|
|
|
|
fn quux(…) fn(i32)
|
|
|
|
|
ma m!(…) macro_rules! m
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
check_empty(
|
|
|
|
|
r"
|
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
|
fn quux(x: i32) {
|
|
|
|
|
m!(x$0);
|
|
|
|
|
}
|
|
|
|
|
",
|
|
|
|
|
expect![[r#"
|
|
|
|
|
kw unsafe
|
|
|
|
|
kw match
|
|
|
|
|
kw while
|
|
|
|
|
kw while let
|
|
|
|
|
kw loop
|
|
|
|
|
kw if
|
|
|
|
|
kw if let
|
|
|
|
|
kw for
|
|
|
|
|
kw true
|
|
|
|
|
kw false
|
|
|
|
|
kw return
|
|
|
|
|
kw self
|
|
|
|
|
kw super
|
|
|
|
|
kw crate
|
|
|
|
|
bt u32
|
|
|
|
|
lc x i32
|
|
|
|
|
fn quux(…) fn(i32)
|
|
|
|
|
ma m!(…) macro_rules! m
|
|
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
check_empty(
|
|
|
|
|
r#"
|
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
|
fn quux(x: i32) {
|
|
|
|
|
let y = 92;
|
|
|
|
|
m!(x$0
|
|
|
|
|
}
|
|
|
|
|
"#,
|
fix: avoid pathological macro expansions
Today, rust-analyzer (and rustc, and bat, and IntelliJ) fail badly on
some kinds of maliciously constructed code, like a deep sequence of
nested parenthesis.
"Who writes 100k nested parenthesis" you'd ask?
Well, in a language with macros, a run-away macro expansion might do
that (see the added tests)! Such expansion can be broad, rather than
deep, so it bypasses recursion check at the macro-expansion layer, but
triggers deep recursion in parser.
In the ideal world, the parser would just handle deeply nested structs
gracefully. We'll get there some day, but at the moment, let's try to be
simple, and just avoid expanding macros with unbalanced parenthesis in
the first place.
closes #9358
2021-08-09 16:06:49 +03:00
|
|
|
expect![[r#""#]],
|
2021-07-23 16:37:19 +02:00
|
|
|
);
|
|
|
|
|
}
|
2021-07-23 17:02:39 +02:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn enum_qualified() {
|
|
|
|
|
check(
|
|
|
|
|
r#"
|
|
|
|
|
impl Enum {
|
|
|
|
|
type AssocType = ();
|
|
|
|
|
const ASSOC_CONST: () = ();
|
|
|
|
|
fn assoc_fn() {}
|
|
|
|
|
}
|
|
|
|
|
fn func() {
|
|
|
|
|
Enum::$0
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
expect![[r#"
|
|
|
|
|
ev TupleV(…) (u32)
|
2021-11-24 16:01:33 +01:00
|
|
|
ev RecordV {field: u32}
|
2021-07-23 17:02:39 +02:00
|
|
|
ev UnitV ()
|
2021-12-21 16:34:55 +01:00
|
|
|
ct ASSOC_CONST const ASSOC_CONST: ()
|
2021-07-23 17:02:39 +02:00
|
|
|
fn assoc_fn() fn()
|
2021-12-21 16:36:04 +01:00
|
|
|
ta AssocType type AssocType = ()
|
2021-07-23 17:02:39 +02:00
|
|
|
"#]],
|
|
|
|
|
);
|
|
|
|
|
}
|