321 lines
6.1 KiB
Rust
Raw Normal View History

2021-03-21 01:00:09 +01:00
//! Completes lifetimes and labels.
2021-03-20 22:43:42 +01:00
use hir::ScopeDef;
use crate::{completions::Completions, context::CompletionContext};
/// Completes lifetimes.
pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.lifetime_allowed {
return;
}
2021-05-27 03:47:20 +02:00
let lp_string;
2021-03-20 22:43:42 +01:00
let param_lifetime = match (
&ctx.lifetime_syntax,
ctx.lifetime_param_syntax.as_ref().and_then(|lp| lp.lifetime()),
) {
(Some(lt), Some(lp)) if lp == lt.clone() => return,
2021-05-27 03:47:20 +02:00
(Some(_), Some(lp)) => {
lp_string = lp.to_string();
Some(&*lp_string)
2021-05-27 03:47:20 +02:00
}
2021-03-20 22:43:42 +01:00
_ => None,
};
ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
if param_lifetime != Some(&*name.to_string()) {
2021-05-27 03:47:20 +02:00
acc.add_resolution(ctx, name, &res);
2021-03-20 22:43:42 +01:00
}
}
});
if param_lifetime.is_none() {
acc.add_static_lifetime(ctx);
}
}
2021-03-21 01:00:09 +01:00
/// Completes labels.
pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.is_label_ref {
return;
}
ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::Label(_) = res {
acc.add_resolution(ctx, name, &res);
2021-03-21 01:00:09 +01:00
}
});
}
2021-03-20 22:43:42 +01:00
#[cfg(test)]
mod tests {
use expect_test::{expect, Expect};
use crate::{
test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
CompletionConfig, CompletionKind,
};
fn check(ra_fixture: &str, expect: Expect) {
check_with_config(TEST_CONFIG, ra_fixture, expect);
}
fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
expect.assert_eq(&actual)
}
#[test]
fn check_lifetime_edit() {
check_edit(
"'lifetime",
r#"
fn func<'lifetime>(foo: &'li$0) {}
"#,
r#"
fn func<'lifetime>(foo: &'lifetime) {}
"#,
);
cov_mark::check!(completes_if_lifetime_without_idents);
check_edit(
"'lifetime",
r#"
fn func<'lifetime>(foo: &'$0) {}
"#,
r#"
fn func<'lifetime>(foo: &'lifetime) {}
2021-03-20 22:43:42 +01:00
"#,
);
}
#[test]
fn complete_lifetime_in_ref() {
check(
r#"
fn foo<'lifetime>(foo: &'a$0 usize) {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
}
#[test]
fn complete_lifetime_in_ref_missing_ty() {
check(
r#"
fn foo<'lifetime>(foo: &'a$0) {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
}
#[test]
fn complete_lifetime_in_self_ref() {
check(
r#"
struct Foo;
impl<'impl> Foo {
fn foo<'func>(&'a$0 self) {}
}
"#,
expect![[r#"
lt 'func
lt 'impl
lt 'static
"#]],
);
}
#[test]
fn complete_lifetime_in_arg_list() {
check(
r#"
struct Foo<'lt>;
fn foo<'lifetime>(_: Foo<'a$0>) {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
}
#[test]
fn complete_lifetime_in_where_pred() {
check(
r#"
fn foo2<'lifetime, T>() where 'a$0 {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
}
#[test]
fn complete_lifetime_in_ty_bound() {
check(
r#"
fn foo2<'lifetime, T>() where T: 'a$0 {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
check(
r#"
fn foo2<'lifetime, T>() where T: Trait<'a$0> {}
"#,
expect![[r#"
lt 'lifetime
lt 'static
"#]],
);
}
#[test]
fn dont_complete_lifetime_in_assoc_ty_bound() {
check(
r#"
fn foo2<'lifetime, T>() where T: Trait<Item = 'a$0> {}
"#,
expect![[r#""#]],
);
}
#[test]
fn complete_lifetime_in_param_list() {
check(
r#"
fn foo<'a$0>() {}
"#,
expect![[r#""#]],
);
check(
r#"
fn foo<'footime, 'lifetime: 'a$0>() {}
"#,
expect![[r#"
lt 'footime
"#]],
);
}
2021-03-21 01:00:09 +01:00
#[test]
fn check_label_edit() {
check_edit(
"'label",
r#"
fn foo() {
'label: loop {
break '$0
}
}
"#,
r#"
fn foo() {
'label: loop {
break 'label
}
}
"#,
);
}
2021-03-21 01:00:09 +01:00
#[test]
fn complete_label_in_loop() {
check(
r#"
fn foo() {
'foop: loop {
break '$0
}
}
"#,
expect![[r#"
lb 'foop
"#]],
);
check(
r#"
fn foo() {
'foop: loop {
continue '$0
}
}
"#,
expect![[r#"
lb 'foop
"#]],
);
}
#[test]
fn complete_label_in_block_nested() {
check(
r#"
fn foo() {
'foop: {
'baap: {
break '$0
}
}
}
"#,
expect![[r#"
lb 'baap
lb 'foop
"#]],
);
}
#[test]
fn complete_label_in_loop_with_value() {
check(
r#"
fn foo() {
'foop: loop {
break '$0 i32;
}
}
"#,
expect![[r#"
lb 'foop
"#]],
);
}
#[test]
fn complete_label_in_while_cond() {
check(
r#"
fn foo() {
'outer: while { 'inner: loop { break '$0 } } {}
}
"#,
expect![[r#"
lb 'inner
lb 'outer
"#]],
);
}
#[test]
fn complete_label_in_for_iterable() {
check(
r#"
fn foo() {
'outer: for _ in [{ 'inner: loop { break '$0 } }] {}
}
"#,
expect![[r#"
lb 'inner
"#]],
);
}
2021-03-20 22:43:42 +01:00
}