Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/remove_parentheses.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/remove_parentheses.rs | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs new file mode 100644 index 0000000000..185beda9d0 --- /dev/null +++ b/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -0,0 +1,91 @@ +use syntax::{ast, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: remove_parentheses +// +// Removes redundant parentheses. +// +// ``` +// fn main() { +// _ = $0(2) + 2; +// } +// ``` +// -> +// ``` +// fn main() { +// _ = 2 + 2; +// } +// ``` +pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let parens = ctx.find_node_at_offset::<ast::ParenExpr>()?; + + let cursor_in_range = + parens.l_paren_token()?.text_range().contains_range(ctx.selection_trimmed()) + || parens.r_paren_token()?.text_range().contains_range(ctx.selection_trimmed()); + if !cursor_in_range { + return None; + } + + 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 { + return None; + } + + let target = parens.syntax().text_range(); + acc.add( + AssistId("remove_parentheses", AssistKind::Refactor), + "Remove redundant parentheses", + target, + |builder| builder.replace_ast(parens.into(), expr), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn remove_parens_simple() { + check_assist(remove_parentheses, r#"fn f() { $0(2) + 2; }"#, r#"fn f() { 2 + 2; }"#); + check_assist(remove_parentheses, r#"fn f() { ($02) + 2; }"#, r#"fn f() { 2 + 2; }"#); + check_assist(remove_parentheses, r#"fn f() { (2)$0 + 2; }"#, r#"fn f() { 2 + 2; }"#); + check_assist(remove_parentheses, r#"fn f() { (2$0) + 2; }"#, r#"fn f() { 2 + 2; }"#); + } + + #[test] + fn remove_parens_precedence() { + check_assist( + remove_parentheses, + r#"fn f() { $0(2 * 3) + 1; }"#, + r#"fn f() { 2 * 3 + 1; }"#, + ); + check_assist(remove_parentheses, r#"fn f() { ( $0(2) ); }"#, r#"fn f() { ( 2 ); }"#); + check_assist(remove_parentheses, r#"fn f() { $0(2?)?; }"#, r#"fn f() { 2??; }"#); + check_assist(remove_parentheses, r#"fn f() { f(($02 + 2)); }"#, r#"fn f() { f(2 + 2); }"#); + check_assist( + remove_parentheses, + r#"fn f() { (1<2)&&$0(3>4); }"#, + r#"fn f() { (1<2)&&3>4; }"#, + ); + } + + #[test] + fn remove_parens_doesnt_apply_precedence() { + check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(2 + 2) * 8; }"#); + check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(2 + 2).f(); }"#); + check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(2 + 2).await; }"#); + check_assist_not_applicable(remove_parentheses, r#"fn f() { $0!(2..2); }"#); + } + + #[test] + fn remove_parens_doesnt_apply_with_cursor_not_on_paren() { + check_assist_not_applicable(remove_parentheses, r#"fn f() { (2 +$0 2) }"#); + check_assist_not_applicable(remove_parentheses, r#"fn f() {$0 (2 + 2) }"#); + } +} |