Skip to content

Commit

Permalink
Auto merge of rust-lang#13764 - WaffleLapkin:badassexprs, r=Veykril
Browse files Browse the repository at this point in the history
fix: Correctly check for parentheses redundancy in `remove_parentheses` assist

This is quite a bunch of code and some hacks, but I _think_ this time it's correct.

I've added a lot of tests, most of which fail with the assist impl from rust-lang#13733 :')
  • Loading branch information
bors committed Dec 20, 2022
2 parents 5c8f00f + babd4c7 commit 927d56a
Show file tree
Hide file tree
Showing 2 changed files with 440 additions and 97 deletions.
136 changes: 133 additions & 3 deletions crates/ide-assists/src/handlers/remove_parentheses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->

let expr = parens.expr()?;

let parent = ast::Expr::cast(parens.syntax().parent()?);
let is_ok_to_remove = expr.precedence() >= parent.as_ref().and_then(ast::Expr::precedence);
if !is_ok_to_remove {
let parent = parens.syntax().parent()?;
if expr.needs_parens_in(parent) {
return None;
}

Expand All @@ -58,6 +57,31 @@ mod tests {
check_assist(remove_parentheses, r#"fn f() { (2$0) + 2; }"#, r#"fn f() { 2 + 2; }"#);
}

#[test]
fn remove_parens_closure() {
check_assist(remove_parentheses, r#"fn f() { &$0(|| 42) }"#, r#"fn f() { &|| 42 }"#);

check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(|| 42).f() }"#);
}

#[test]
fn remove_parens_if_let_chains() {
check_assist_not_applicable(
remove_parentheses,
r#"fn f() { if let true = $0(true && true) {} }"#,
);
}

#[test]
fn remove_parens_associativity() {
check_assist(
remove_parentheses,
r#"fn f() { $0(2 + 2) + 2; }"#,
r#"fn f() { 2 + 2 + 2; }"#,
);
check_assist_not_applicable(remove_parentheses, r#"fn f() { 2 + $0(2 + 2); }"#);
}

#[test]
fn remove_parens_precedence() {
check_assist(
Expand Down Expand Up @@ -88,4 +112,110 @@ mod tests {
check_assist_not_applicable(remove_parentheses, r#"fn f() { (2 +$0 2) }"#);
check_assist_not_applicable(remove_parentheses, r#"fn f() {$0 (2 + 2) }"#);
}

#[test]
fn remove_parens_doesnt_apply_when_expr_would_be_turned_into_a_statement() {
check_assist_not_applicable(remove_parentheses, r#"fn x() -> u8 { $0({ 0 } + 1) }"#);
check_assist_not_applicable(
remove_parentheses,
r#"fn x() -> u8 { $0(if true { 0 } else { 1 } + 1) }"#,
);
check_assist_not_applicable(remove_parentheses, r#"fn x() -> u8 { $0(loop {} + 1) }"#);
}

#[test]
fn remove_parens_doesnt_apply_weird_syntax_and_adge_cases() {
// removing `()` would break code because {} would be counted as the loop/if body
check_assist_not_applicable(remove_parentheses, r#"fn f() { for _ in $0(0..{3}) {} }"#);
check_assist_not_applicable(remove_parentheses, r#"fn f() { for _ in $0(S {}) {} }"#);
check_assist_not_applicable(remove_parentheses, r#"fn f() { if $0(S {} == 2) {} }"#);
check_assist_not_applicable(remove_parentheses, r#"fn f() { if $0(return) {} }"#);
}

#[test]
fn remove_parens_return_with_value_followed_by_block() {
check_assist(
remove_parentheses,
r#"fn f() { if $0(return ()) {} }"#,
r#"fn f() { if return () {} }"#,
);
}

#[test]
fn remove_exprs_let_else_restrictions() {
// `}` is not allowed before `else` here
check_assist_not_applicable(
remove_parentheses,
r#"fn f() { let _ = $0(S{}) else { return }; }"#,
);

// logic operators can't directly appear in the let-else
check_assist_not_applicable(
remove_parentheses,
r#"fn f() { let _ = $0(false || false) else { return }; }"#,
);
check_assist_not_applicable(
remove_parentheses,
r#"fn f() { let _ = $0(true && true) else { return }; }"#,
);
}

#[test]
fn remove_parens_weird_places() {
check_assist(
remove_parentheses,
r#"fn f() { match () { _=>$0(()) } }"#,
r#"fn f() { match () { _=>() } }"#,
);

check_assist(
remove_parentheses,
r#"fn x() -> u8 { { [$0({ 0 } + 1)] } }"#,
r#"fn x() -> u8 { { [{ 0 } + 1] } }"#,
);
}

#[test]
fn remove_parens_return_dot_f() {
check_assist(
remove_parentheses,
r#"fn f() { $0(return).f() }"#,
r#"fn f() { return.f() }"#,
);
}

#[test]
fn remove_parens_prefix_then_return_something() {
check_assist(
remove_parentheses,
r#"fn f() { &$0(return ()) }"#,
r#"fn f() { &return () }"#,
);
}

#[test]
fn remove_parens_double_paren_stmt() {
check_assist(
remove_parentheses,
r#"fn x() -> u8 { $0(({ 0 } + 1)) }"#,
r#"fn x() -> u8 { ({ 0 } + 1) }"#,
);

check_assist(
remove_parentheses,
r#"fn x() -> u8 { (($0{ 0 } + 1)) }"#,
r#"fn x() -> u8 { ({ 0 } + 1) }"#,
);
}

#[test]
fn remove_parens_im_tired_of_naming_tests() {
check_assist(
remove_parentheses,
r#"fn f() { 2 + $0(return 2) }"#,
r#"fn f() { 2 + return 2 }"#,
);

check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(return 2) + 2 }"#);
}
}
Loading

0 comments on commit 927d56a

Please sign in to comment.