mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
Handle IfLet in convert_to_guarded_return.
This commit is contained in:
parent
998088876d
commit
4a4d9f7a90
2 changed files with 171 additions and 28 deletions
|
@ -37,7 +37,9 @@ use crate::{
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||||
let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
|
let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
|
||||||
let expr = if_expr.condition()?.expr()?;
|
let cond = if_expr.condition()?;
|
||||||
|
let pat = &cond.pat();
|
||||||
|
let expr = cond.expr()?;
|
||||||
let then_block = if_expr.then_branch()?.block()?;
|
let then_block = if_expr.then_branch()?.block()?;
|
||||||
if if_expr.else_branch().is_some() {
|
if if_expr.else_branch().is_some() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -63,8 +65,8 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
|
||||||
let parent_container = parent_block.syntax().parent()?.parent()?;
|
let parent_container = parent_block.syntax().parent()?.parent()?;
|
||||||
|
|
||||||
let early_expression = match parent_container.kind() {
|
let early_expression = match parent_container.kind() {
|
||||||
WHILE_EXPR | LOOP_EXPR => Some("continue;"),
|
WHILE_EXPR | LOOP_EXPR => Some("continue"),
|
||||||
FN_DEF => Some("return;"),
|
FN_DEF => Some("return"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -77,31 +79,67 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
|
||||||
|
|
||||||
ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
|
ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
|
||||||
let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
|
let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
|
||||||
let new_if_expr =
|
let new_block = match pat {
|
||||||
if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
|
None => {
|
||||||
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
|
// If.
|
||||||
let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
|
let early_expression = &(early_expression.to_owned() + ";");
|
||||||
let end_of_then =
|
let new_if_expr =
|
||||||
if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
|
if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
|
||||||
end_of_then.prev_sibling_or_token().unwrap()
|
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
|
||||||
} else {
|
let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
|
||||||
end_of_then
|
let end_of_then =
|
||||||
};
|
if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
|
||||||
let mut new_if_and_then_statements = new_if_expr.syntax().children_with_tokens().chain(
|
end_of_then.prev_sibling_or_token().unwrap()
|
||||||
then_block_items
|
} else {
|
||||||
.syntax()
|
end_of_then
|
||||||
.children_with_tokens()
|
};
|
||||||
.skip(1)
|
let mut new_if_and_then_statements =
|
||||||
.take_while(|i| *i != end_of_then),
|
new_if_expr.syntax().children_with_tokens().chain(
|
||||||
);
|
then_block_items
|
||||||
let new_block = replace_children(
|
.syntax()
|
||||||
&parent_block.syntax(),
|
.children_with_tokens()
|
||||||
RangeInclusive::new(
|
.skip(1)
|
||||||
if_expr.clone().syntax().clone().into(),
|
.take_while(|i| *i != end_of_then),
|
||||||
if_expr.syntax().clone().into(),
|
);
|
||||||
),
|
replace_children(
|
||||||
&mut new_if_and_then_statements,
|
&parent_block.syntax(),
|
||||||
);
|
RangeInclusive::new(
|
||||||
|
if_expr.clone().syntax().clone().into(),
|
||||||
|
if_expr.syntax().clone().into(),
|
||||||
|
),
|
||||||
|
&mut new_if_and_then_statements,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// If-let.
|
||||||
|
let new_match_expr =
|
||||||
|
if_indent_level.increase_indent(make::let_match_early(expr, early_expression));
|
||||||
|
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
|
||||||
|
let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
|
||||||
|
let end_of_then =
|
||||||
|
if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
|
||||||
|
end_of_then.prev_sibling_or_token().unwrap()
|
||||||
|
} else {
|
||||||
|
end_of_then
|
||||||
|
};
|
||||||
|
let mut then_statements = new_match_expr.syntax().children_with_tokens().chain(
|
||||||
|
then_block_items
|
||||||
|
.syntax()
|
||||||
|
.children_with_tokens()
|
||||||
|
.skip(1)
|
||||||
|
.take_while(|i| *i != end_of_then),
|
||||||
|
);
|
||||||
|
let new_block = replace_children(
|
||||||
|
&parent_block.syntax(),
|
||||||
|
RangeInclusive::new(
|
||||||
|
if_expr.clone().syntax().clone().into(),
|
||||||
|
if_expr.syntax().clone().into(),
|
||||||
|
),
|
||||||
|
&mut then_statements,
|
||||||
|
);
|
||||||
|
new_block
|
||||||
|
}
|
||||||
|
};
|
||||||
edit.target(if_expr.syntax().text_range());
|
edit.target(if_expr.syntax().text_range());
|
||||||
edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
|
edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
|
||||||
edit.set_cursor(cursor_position);
|
edit.set_cursor(cursor_position);
|
||||||
|
@ -143,6 +181,37 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_let_inside_fn() {
|
||||||
|
check_assist(
|
||||||
|
convert_to_guarded_return,
|
||||||
|
r#"
|
||||||
|
fn main(n: Option<String>) {
|
||||||
|
bar();
|
||||||
|
if<|> let Some(n) = n {
|
||||||
|
foo(n);
|
||||||
|
|
||||||
|
//comment
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main(n: Option<String>) {
|
||||||
|
bar();
|
||||||
|
le<|>t n = match n {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
foo(n);
|
||||||
|
|
||||||
|
//comment
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn convert_inside_while() {
|
fn convert_inside_while() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -171,6 +240,35 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_let_inside_while() {
|
||||||
|
check_assist(
|
||||||
|
convert_to_guarded_return,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
while true {
|
||||||
|
if<|> let Some(n) = n {
|
||||||
|
foo(n);
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
while true {
|
||||||
|
le<|>t n = match n {
|
||||||
|
Some(it) => it,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
foo(n);
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn convert_inside_loop() {
|
fn convert_inside_loop() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -199,6 +297,35 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_let_inside_loop() {
|
||||||
|
check_assist(
|
||||||
|
convert_to_guarded_return,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
if<|> let Some(n) = n {
|
||||||
|
foo(n);
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
le<|>t n = match n {
|
||||||
|
Some(it) => it,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
foo(n);
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignore_already_converted_if() {
|
fn ignore_already_converted_if() {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
|
|
|
@ -110,6 +110,22 @@ pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchAr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn let_match_early(expr: ast::Expr, early_expression: &str) -> ast::LetStmt {
|
||||||
|
return from_text(&format!(
|
||||||
|
r#"let {} = match {} {{
|
||||||
|
Some(it) => it,
|
||||||
|
None => {},
|
||||||
|
}};"#,
|
||||||
|
expr.syntax().text(),
|
||||||
|
expr.syntax().text(),
|
||||||
|
early_expression
|
||||||
|
));
|
||||||
|
|
||||||
|
fn from_text(text: &str) -> ast::LetStmt {
|
||||||
|
ast_from_text(&format!("fn f() {{ {} }}", text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>) -> ast::WherePred {
|
pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>) -> ast::WherePred {
|
||||||
let bounds = bounds.map(|b| b.syntax().to_string()).join(" + ");
|
let bounds = bounds.map(|b| b.syntax().to_string()).join(" + ");
|
||||||
return from_text(&format!("{}: {}", path.syntax(), bounds));
|
return from_text(&format!("{}: {}", path.syntax(), bounds));
|
||||||
|
|
Loading…
Reference in a new issue