1 //! Completes lifetimes and labels.
3 //! These completions work a bit differently in that they are only shown when what the user types
4 //! has a `'` preceding it, as our fake syntax tree is invalid otherwise (due to us not inserting
5 //! a lifetime but an ident for obvious reasons).
6 //! Due to this all the tests for lifetimes and labels live in this module for the time being as
7 //! there is no value in lifting these out into the outline module test since they will either not
8 //! show up for normal completions, or they won't show completions other than lifetimes depending
9 //! on the fixture input.
10 use hir::{known, ScopeDef};
11 use syntax::{ast, TokenText};
14 completions::Completions,
15 context::{CompletionContext, LifetimeContext, LifetimeKind},
18 /// Completes lifetimes.
19 pub(crate) fn complete_lifetime(
20 acc: &mut Completions,
21 ctx: &CompletionContext<'_>,
22 lifetime_ctx: &LifetimeContext,
24 let (lp, lifetime) = match lifetime_ctx {
25 LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime),
27 kind: LifetimeKind::LifetimeParam { is_decl: false, param },
29 } => (Some(param), lifetime),
32 let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) {
33 (Some(lt), Some(lp)) if lp == lt.clone() => return,
34 (Some(_), Some(lp)) => Some(lp),
37 let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text);
38 let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str);
40 ctx.process_all_names_raw(&mut |name, res| {
43 ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
44 if param_lifetime != Some(&*name.to_smol_str())
46 acc.add_lifetime(ctx, name);
49 if param_lifetime.is_none() {
50 acc.add_lifetime(ctx, known::STATIC_LIFETIME);
55 pub(crate) fn complete_label(
56 acc: &mut Completions,
57 ctx: &CompletionContext<'_>,
58 lifetime_ctx: &LifetimeContext,
60 if !matches!(lifetime_ctx, LifetimeContext { kind: LifetimeKind::LabelRef, .. }) {
63 ctx.process_all_names_raw(&mut |name, res| {
64 if let ScopeDef::Label(_) = res {
65 acc.add_label(ctx, name);
72 use expect_test::{expect, Expect};
74 use crate::tests::{check_edit, completion_list};
76 fn check(ra_fixture: &str, expect: Expect) {
77 let actual = completion_list(ra_fixture);
78 expect.assert_eq(&actual);
82 fn check_lifetime_edit() {
86 fn func<'lifetime>(foo: &'li$0) {}
89 fn func<'lifetime>(foo: &'lifetime) {}
92 cov_mark::check!(completes_if_lifetime_without_idents);
96 fn func<'lifetime>(foo: &'$0) {}
99 fn func<'lifetime>(foo: &'lifetime) {}
105 fn complete_lifetime_in_ref() {
108 fn foo<'lifetime>(foo: &'a$0 usize) {}
118 fn complete_lifetime_in_ref_missing_ty() {
121 fn foo<'lifetime>(foo: &'a$0) {}
130 fn complete_lifetime_in_self_ref() {
135 fn foo<'func>(&'a$0 self) {}
147 fn complete_lifetime_in_arg_list() {
151 fn foo<'lifetime>(_: Foo<'a$0>) {}
161 fn complete_lifetime_in_where_pred() {
164 fn foo2<'lifetime, T>() where 'a$0 {}
174 fn complete_lifetime_in_ty_bound() {
177 fn foo2<'lifetime, T>() where T: 'a$0 {}
186 fn foo2<'lifetime, T>() where T: Trait<'a$0> {}
196 fn dont_complete_lifetime_in_assoc_ty_bound() {
199 fn foo2<'lifetime, T>() where T: Trait<Item = 'a$0> {}
206 fn complete_lifetime_in_param_list() {
221 fn foo<'footime, 'lifetime: 'a$0>() {}
230 fn check_label_edit() {
251 fn complete_label_in_loop() {
279 fn complete_label_in_block_nested() {
298 fn complete_label_in_loop_with_value() {
314 fn complete_label_in_while_cond() {
318 'outer: while { 'inner: loop { break '$0 } } {}
329 fn complete_label_in_for_iterable() {
333 'outer: for _ in [{ 'inner: loop { break '$0 } }] {}