Make "pull assignments up" assist work in more cases

This commit is contained in:
Jesse Bakker 2021-05-11 14:22:51 +02:00
parent 6cd11bbbc2
commit 5f37e34406

View File

@ -60,6 +60,12 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
return None; return None;
}; };
if let Some(parent) = tgt.syntax().parent() {
if matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) {
return None;
}
}
acc.add( acc.add(
AssistId("pull_assignment_up", AssistKind::RefactorExtract), AssistId("pull_assignment_up", AssistKind::RefactorExtract),
"Pull assignment up", "Pull assignment up",
@ -74,7 +80,13 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
let tgt = edit.make_ast_mut(tgt); let tgt = edit.make_ast_mut(tgt);
for (stmt, rhs) in assignments { for (stmt, rhs) in assignments {
ted::replace(stmt.syntax(), rhs.syntax()); let mut stmt = stmt.syntax().clone();
if let Some(parent) = stmt.parent() {
if ast::ExprStmt::cast(parent.clone()).is_some() {
stmt = parent.clone();
}
}
ted::replace(stmt, rhs.syntax());
} }
let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone()); let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone());
let assign_stmt = make::expr_stmt(assign_expr); let assign_stmt = make::expr_stmt(assign_expr);
@ -87,7 +99,7 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
struct AssignmentsCollector<'a> { struct AssignmentsCollector<'a> {
sema: &'a hir::Semantics<'a, ide_db::RootDatabase>, sema: &'a hir::Semantics<'a, ide_db::RootDatabase>,
common_lhs: ast::Expr, common_lhs: ast::Expr,
assignments: Vec<(ast::ExprStmt, ast::Expr)>, assignments: Vec<(ast::BinExpr, ast::Expr)>,
} }
impl<'a> AssignmentsCollector<'a> { impl<'a> AssignmentsCollector<'a> {
@ -95,6 +107,7 @@ impl<'a> AssignmentsCollector<'a> {
for arm in match_expr.match_arm_list()?.arms() { for arm in match_expr.match_arm_list()?.arms() {
match arm.expr()? { match arm.expr()? {
ast::Expr::BlockExpr(block) => self.collect_block(&block)?, ast::Expr::BlockExpr(block) => self.collect_block(&block)?,
ast::Expr::BinExpr(expr) => self.collect_expr(&expr)?,
_ => return None, _ => return None,
} }
} }
@ -114,24 +127,30 @@ impl<'a> AssignmentsCollector<'a> {
} }
} }
fn collect_block(&mut self, block: &ast::BlockExpr) -> Option<()> { fn collect_block(&mut self, block: &ast::BlockExpr) -> Option<()> {
if block.tail_expr().is_some() { let last_expr = block.tail_expr().or_else(|| {
return None; if let ast::Stmt::ExprStmt(stmt) = block.statements().last()? {
} stmt.expr()
} else {
let last_stmt = block.statements().last()?; None
if let ast::Stmt::ExprStmt(stmt) = last_stmt {
if let ast::Expr::BinExpr(expr) = stmt.expr()? {
if expr.op_kind()? == ast::BinOp::Assignment
&& is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs)
{
self.assignments.push((stmt, expr.rhs()?));
return Some(());
}
} }
})?;
if let ast::Expr::BinExpr(expr) = last_expr {
return self.collect_expr(&expr);
} }
None None
} }
fn collect_expr(&mut self, expr: &ast::BinExpr) -> Option<()> {
if expr.op_kind()? == ast::BinOp::Assignment
&& is_equivalent(self.sema, &expr.lhs()?, &self.common_lhs)
{
self.assignments.push((expr.clone(), expr.rhs()?));
return Some(());
}
None
}
} }
fn is_equivalent( fn is_equivalent(
@ -241,7 +260,6 @@ fn foo() {
} }
#[test] #[test]
#[ignore]
fn test_pull_assignment_up_assignment_expressions() { fn test_pull_assignment_up_assignment_expressions() {
check_assist( check_assist(
pull_assignment_up, pull_assignment_up,