Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/add_label_to_loop.rs')
-rw-r--r--crates/ide-assists/src/handlers/add_label_to_loop.rs93
1 files changed, 82 insertions, 11 deletions
diff --git a/crates/ide-assists/src/handlers/add_label_to_loop.rs b/crates/ide-assists/src/handlers/add_label_to_loop.rs
index b84ad24cfc..6a408e5254 100644
--- a/crates/ide-assists/src/handlers/add_label_to_loop.rs
+++ b/crates/ide-assists/src/handlers/add_label_to_loop.rs
@@ -3,11 +3,7 @@ use ide_db::{
};
use syntax::{
SyntaxToken, T,
- ast::{
- self, AstNode, HasLoopBody,
- make::{self, tokens},
- syntax_factory::SyntaxFactory,
- },
+ ast::{self, AstNode, HasLoopBody, syntax_factory::SyntaxFactory},
syntax_editor::{Position, SyntaxEditor},
};
@@ -35,9 +31,9 @@ use crate::{AssistContext, AssistId, Assists};
// }
// ```
pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
- let loop_kw = ctx.find_token_syntax_at_offset(T![loop])?;
- let loop_expr = loop_kw.parent().and_then(ast::LoopExpr::cast)?;
- if loop_expr.label().is_some() {
+ let loop_expr = ctx.find_node_at_offset::<ast::AnyHasLoopBody>()?;
+ let loop_kw = loop_token(&loop_expr)?;
+ if loop_expr.label().is_some() || !loop_kw.text_range().contains_inclusive(ctx.offset()) {
return None;
}
@@ -52,8 +48,8 @@ pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
let label = make.lifetime("'l");
let elements = vec![
label.syntax().clone().into(),
- make::token(T![:]).into(),
- tokens::single_space().into(),
+ make.token(T![:]).into(),
+ make.whitespace(" ").into(),
];
editor.insert_all(Position::before(&loop_kw), elements);
@@ -80,6 +76,14 @@ pub(crate) fn add_label_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
)
}
+fn loop_token(loop_expr: &ast::AnyHasLoopBody) -> Option<syntax::SyntaxToken> {
+ loop_expr
+ .syntax()
+ .children_with_tokens()
+ .filter_map(|it| it.into_token())
+ .find(|it| matches!(it.kind(), T![for] | T![loop] | T![while]))
+}
+
fn insert_label_after_token(
editor: &mut SyntaxEditor,
make: &SyntaxFactory,
@@ -88,7 +92,7 @@ fn insert_label_after_token(
builder: &mut SourceChangeBuilder,
) {
let label = make.lifetime("'l");
- let elements = vec![tokens::single_space().into(), label.syntax().clone().into()];
+ let elements = vec![make.whitespace(" ").into(), label.syntax().clone().into()];
editor.insert_all(Position::after(token), elements);
if let Some(cap) = ctx.config.snippet_cap {
@@ -124,6 +128,48 @@ fn main() {
}
#[test]
+ fn add_label_to_while_expr() {
+ check_assist(
+ add_label_to_loop,
+ r#"
+fn main() {
+ while$0 true {
+ break;
+ continue;
+ }
+}"#,
+ r#"
+fn main() {
+ ${1:'l}: while true {
+ break ${2:'l};
+ continue ${0:'l};
+ }
+}"#,
+ );
+ }
+
+ #[test]
+ fn add_label_to_for_expr() {
+ check_assist(
+ add_label_to_loop,
+ r#"
+fn main() {
+ for$0 _ in 0..5 {
+ break;
+ continue;
+ }
+}"#,
+ r#"
+fn main() {
+ ${1:'l}: for _ in 0..5 {
+ break ${2:'l};
+ continue ${0:'l};
+ }
+}"#,
+ );
+ }
+
+ #[test]
fn add_label_to_outer_loop() {
check_assist(
add_label_to_loop,
@@ -194,4 +240,29 @@ fn main() {
}"#,
);
}
+
+ #[test]
+ fn do_not_add_label_if_outside_keyword() {
+ check_assist_not_applicable(
+ add_label_to_loop,
+ r#"
+fn main() {
+ 'l: loop {$0
+ break 'l;
+ continue 'l;
+ }
+}"#,
+ );
+
+ check_assist_not_applicable(
+ add_label_to_loop,
+ r#"
+fn main() {
+ 'l: while true {$0
+ break 'l;
+ continue 'l;
+ }
+}"#,
+ );
+ }
}