aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs77
-rw-r--r--crates/ide_completion/src/context.rs28
-rw-r--r--crates/ide_completion/src/lib.rs1
-rw-r--r--crates/ide_completion/src/render.rs1
4 files changed, 100 insertions, 7 deletions
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs
index 74eb23360..07be28e9c 100644
--- a/crates/ide_completion/src/completions/lifetime.rs
+++ b/crates/ide_completion/src/completions/lifetime.rs
@@ -1,4 +1,4 @@
1//! Completes lifetimes. 1//! Completes lifetimes and labels.
2use hir::ScopeDef; 2use hir::ScopeDef;
3 3
4use crate::{completions::Completions, context::CompletionContext}; 4use crate::{completions::Completions, context::CompletionContext};
@@ -29,6 +29,18 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
29 } 29 }
30} 30}
31 31
32/// Completes labels.
33pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
34 if !ctx.is_label_ref {
35 return;
36 }
37 ctx.scope.process_all_names(&mut |name, res| {
38 if let ScopeDef::Label(_) = res {
39 acc.add_resolution(ctx, name.to_string(), &res);
40 }
41 });
42}
43
32#[cfg(test)] 44#[cfg(test)]
33mod tests { 45mod tests {
34 use expect_test::{expect, Expect}; 46 use expect_test::{expect, Expect};
@@ -178,4 +190,67 @@ fn foo<'footime, 'lifetime: 'a$0>() {}
178 "#]], 190 "#]],
179 ); 191 );
180 } 192 }
193
194 #[test]
195 fn complete_label_in_loop() {
196 check(
197 r#"
198fn foo() {
199 'foop: loop {
200 break '$0
201 }
202}
203"#,
204 expect![[r#"
205 lb 'foop
206 "#]],
207 );
208 check(
209 r#"
210fn foo() {
211 'foop: loop {
212 continue '$0
213 }
214}
215"#,
216 expect![[r#"
217 lb 'foop
218 "#]],
219 );
220 }
221
222 #[test]
223 fn complete_label_in_block_nested() {
224 check(
225 r#"
226fn foo() {
227 'foop: {
228 'baap: {
229 break '$0
230 }
231 }
232}
233"#,
234 expect![[r#"
235 lb 'baap
236 lb 'foop
237 "#]],
238 );
239 }
240
241 #[test]
242 fn complete_label_in_loop_with_value() {
243 check(
244 r#"
245fn foo() {
246 'foop: loop {
247 break '$0 i32;
248 }
249}
250"#,
251 expect![[r#"
252 lb 'foop
253 "#]],
254 );
255 }
181} 256}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 4c2b31084..6cb7e5264 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -53,6 +53,7 @@ pub(crate) struct CompletionContext<'a> {
53 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 53 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
54 pub(super) active_parameter: Option<ActiveParameter>, 54 pub(super) active_parameter: Option<ActiveParameter>,
55 pub(super) is_param: bool, 55 pub(super) is_param: bool,
56 pub(super) is_label_ref: bool,
56 /// If a name-binding or reference to a const in a pattern. 57 /// If a name-binding or reference to a const in a pattern.
57 /// Irrefutable patterns (like let) are excluded. 58 /// Irrefutable patterns (like let) are excluded.
58 pub(super) is_pat_binding_or_const: bool, 59 pub(super) is_pat_binding_or_const: bool,
@@ -155,6 +156,7 @@ impl<'a> CompletionContext<'a> {
155 record_field_syntax: None, 156 record_field_syntax: None,
156 impl_def: None, 157 impl_def: None,
157 active_parameter: ActiveParameter::at(db, position), 158 active_parameter: ActiveParameter::at(db, position),
159 is_label_ref: false,
158 is_param: false, 160 is_param: false,
159 is_pat_binding_or_const: false, 161 is_pat_binding_or_const: false,
160 is_irrefutable_pat_binding: false, 162 is_irrefutable_pat_binding: false,
@@ -468,12 +470,26 @@ impl<'a> CompletionContext<'a> {
468 ) { 470 ) {
469 self.lifetime_syntax = 471 self.lifetime_syntax =
470 find_node_at_offset(original_file, lifetime.syntax().text_range().start()); 472 find_node_at_offset(original_file, lifetime.syntax().text_range().start());
471 if lifetime.syntax().parent().map_or(false, |p| p.kind() != syntax::SyntaxKind::ERROR) { 473 if let Some(parent) = lifetime.syntax().parent() {
472 self.lifetime_allowed = true; 474 if parent.kind() == syntax::SyntaxKind::ERROR {
473 } 475 return;
474 if let Some(_) = lifetime.syntax().parent().and_then(ast::LifetimeParam::cast) { 476 }
475 self.lifetime_param_syntax = 477
476 self.sema.find_node_at_offset_with_macros(original_file, offset); 478 if parent.kind() != syntax::SyntaxKind::LABEL {
479 match_ast! {
480 match parent {
481 ast::LifetimeParam(_it) => {
482 self.lifetime_allowed = true;
483 self.lifetime_param_syntax =
484 self.sema.find_node_at_offset_with_macros(original_file, offset);
485 },
486 ast::BreakExpr(_it) => self.is_label_ref = true,
487 ast::ContinueExpr(_it) => self.is_label_ref = true,
488 ast::Label(_it) => (),
489 _ => self.lifetime_allowed = true,
490 }
491 }
492 }
477 } 493 }
478 } 494 }
479 495
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 7a0eb6a96..995970fca 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -131,6 +131,7 @@ pub fn completions(
131 completions::mod_::complete_mod(&mut acc, &ctx); 131 completions::mod_::complete_mod(&mut acc, &ctx);
132 completions::flyimport::import_on_the_fly(&mut acc, &ctx); 132 completions::flyimport::import_on_the_fly(&mut acc, &ctx);
133 completions::lifetime::complete_lifetime(&mut acc, &ctx); 133 completions::lifetime::complete_lifetime(&mut acc, &ctx);
134 completions::lifetime::complete_label(&mut acc, &ctx);
134 135
135 Some(acc) 136 Some(acc)
136} 137}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 2b6e9ebd1..23e00aa47 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -219,6 +219,7 @@ impl<'a> Render<'a> {
219 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, 219 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
220 }), 220 }),
221 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), 221 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
222 ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
222 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => { 223 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
223 CompletionItemKind::SymbolKind(SymbolKind::SelfParam) 224 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
224 } 225 }