Skip to content

Commit 1479dd6

Browse files
bors[bot]matklad
andauthored
Merge #3045
3045: Cleanup early return assist r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 5aba5a7 + 36ee9ec commit 1479dd6

File tree

4 files changed

+64
-29
lines changed

4 files changed

+64
-29
lines changed

crates/ra_assists/src/assists/apply_demorgan.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
3131
if !cursor_in_range {
3232
return None;
3333
}
34+
3435
let lhs = expr.lhs()?;
3536
let lhs_range = lhs.syntax().text_range();
37+
let not_lhs = invert_boolean_expression(lhs);
38+
3639
let rhs = expr.rhs()?;
3740
let rhs_range = rhs.syntax().text_range();
38-
let not_lhs = invert_boolean_expression(&lhs)?;
39-
let not_rhs = invert_boolean_expression(&rhs)?;
41+
let not_rhs = invert_boolean_expression(rhs);
4042

4143
ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| {
4244
edit.target(op_range);
@@ -77,12 +79,12 @@ mod tests {
7779
}
7880

7981
#[test]
80-
fn demorgan_doesnt_apply_with_cursor_not_on_op() {
81-
check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }")
82+
fn demorgan_general_case() {
83+
check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x &&<|> !x) }")
8284
}
8385

8486
#[test]
85-
fn demorgan_doesnt_apply_when_operands_arent_negated_already() {
86-
check_assist_not_applicable(apply_demorgan, "fn f() { x ||<|> x }")
87+
fn demorgan_doesnt_apply_with_cursor_not_on_op() {
88+
check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }")
8789
}
8890
}

crates/ra_assists/src/assists/early_return.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use ra_syntax::{
1010

1111
use crate::{
1212
assist_ctx::{Assist, AssistCtx},
13+
assists::invert_if::invert_boolean_expression,
1314
AssistId,
1415
};
1516

@@ -99,9 +100,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
99100
let new_block = match if_let_pat {
100101
None => {
101102
// If.
102-
let early_expression = &(early_expression.syntax().to_string() + ";");
103-
let new_expr = if_indent_level
104-
.increase_indent(make::if_expression(cond_expr, early_expression));
103+
let new_expr = {
104+
let then_branch =
105+
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
106+
let cond = invert_boolean_expression(cond_expr);
107+
let e = make::expr_if(cond, then_branch);
108+
if_indent_level.increase_indent(e)
109+
};
105110
replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
106111
}
107112
Some((path, bound_ident)) => {

crates/ra_assists/src/assists/invert_if.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ra_syntax::ast::{self, AstNode};
1+
use ra_syntax::ast::{self, make, AstNode};
22
use ra_syntax::T;
33

44
use crate::{Assist, AssistCtx, AssistId};
@@ -35,8 +35,8 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
3535
let then_node = expr.then_branch()?.syntax().clone();
3636

3737
if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
38-
let flip_cond = invert_boolean_expression(&cond)?;
3938
let cond_range = cond.syntax().text_range();
39+
let flip_cond = invert_boolean_expression(cond);
4040
let else_node = else_block.syntax();
4141
let else_range = else_node.text_range();
4242
let then_range = then_node.text_range();
@@ -51,16 +51,23 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
5151
None
5252
}
5353

54-
pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option<ast::Expr> {
54+
pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
55+
if let Some(expr) = invert_special_case(&expr) {
56+
return expr;
57+
}
58+
make::expr_prefix(T![!], expr)
59+
}
60+
61+
pub(crate) fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
5562
match expr {
5663
ast::Expr::BinExpr(bin) => match bin.op_kind()? {
5764
ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
65+
ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
5866
_ => None,
5967
},
60-
ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
61-
ast::PrefixOp::Not => pe.expr(),
62-
_ => None,
63-
},
68+
ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
69+
// FIXME:
70+
// ast::Expr::Literal(true | false )
6471
_ => None,
6572
}
6673
}
@@ -90,12 +97,16 @@ mod tests {
9097
}
9198

9299
#[test]
93-
fn invert_if_doesnt_apply_with_cursor_not_on_if() {
94-
check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
100+
fn invert_if_general_case() {
101+
check_assist(
102+
invert_if,
103+
"fn f() { i<|>f cond { 3 * 2 } else { 1 } }",
104+
"fn f() { i<|>f !cond { 1 } else { 3 * 2 } }",
105+
)
95106
}
96107

97108
#[test]
98-
fn invert_if_doesnt_apply_without_negated() {
99-
check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }")
109+
fn invert_if_doesnt_apply_with_cursor_not_on_if() {
110+
check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
100111
}
101112
}

crates/ra_syntax/src/ast/make.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordF
3333
}
3434
}
3535

36+
pub fn block_expr(
37+
stmts: impl IntoIterator<Item = ast::Stmt>,
38+
tail_expr: Option<ast::Expr>,
39+
) -> ast::BlockExpr {
40+
let mut text = "{\n".to_string();
41+
for stmt in stmts.into_iter() {
42+
text += &format!(" {}\n", stmt.syntax());
43+
}
44+
if let Some(tail_expr) = tail_expr {
45+
text += &format!(" {}\n", tail_expr.syntax())
46+
}
47+
text += "}";
48+
ast_from_text(&format!("fn f() {}", text))
49+
}
50+
3651
pub fn block_from_expr(e: ast::Expr) -> ast::Block {
3752
return from_text(&format!("{{ {} }}", e.syntax()));
3853

@@ -62,6 +77,13 @@ pub fn expr_return() -> ast::Expr {
6277
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
6378
expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
6479
}
80+
pub fn expr_if(condition: ast::Expr, then_branch: ast::BlockExpr) -> ast::Expr {
81+
expr_from_text(&format!("if {} {}", condition.syntax(), then_branch.syntax()))
82+
}
83+
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
84+
let token = token(op);
85+
expr_from_text(&format!("{}{}", token, expr.syntax()))
86+
}
6587
fn expr_from_text(text: &str) -> ast::Expr {
6688
ast_from_text(&format!("const C: () = {};", text))
6789
}
@@ -158,21 +180,16 @@ pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::Whe
158180
}
159181
}
160182

161-
pub fn if_expression(condition: ast::Expr, statement: &str) -> ast::IfExpr {
162-
ast_from_text(&format!(
163-
"fn f() {{ if !{} {{\n {}\n}}\n}}",
164-
condition.syntax().text(),
165-
statement
166-
))
167-
}
168-
169183
pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
170184
let text = match initializer {
171185
Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
172186
None => format!("let {};", pattern.syntax()),
173187
};
174188
ast_from_text(&format!("fn f() {{ {} }}", text))
175189
}
190+
pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
191+
ast_from_text(&format!("fn f() {{ {}; }}", expr.syntax()))
192+
}
176193

177194
pub fn token(kind: SyntaxKind) -> SyntaxToken {
178195
tokens::SOURCE_FILE
@@ -203,7 +220,7 @@ pub mod tokens {
203220
use once_cell::sync::Lazy;
204221

205222
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
206-
Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;"));
223+
Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;"));
207224

208225
pub fn comma() -> SyntaxToken {
209226
SOURCE_FILE

0 commit comments

Comments
 (0)