Unnamed repository; edit this file 'description' to name the repository.
fix: don't remove parentheses for calls of function-like pointers that are members of a struct or union
davidsemakula 2024-06-21
parent 67f7eb5 · commit d6d45a2
-rw-r--r--crates/ide-assists/src/handlers/remove_parentheses.rs29
-rw-r--r--crates/syntax/src/ast/prec.rs8
2 files changed, 37 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs
index 799d36be93..f74fc26112 100644
--- a/crates/ide-assists/src/handlers/remove_parentheses.rs
+++ b/crates/ide-assists/src/handlers/remove_parentheses.rs
@@ -239,4 +239,33 @@ mod tests {
check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(return 2) + 2 }"#);
}
+
+ #[test]
+ fn remove_parens_indirect_calls() {
+ check_assist(
+ remove_parentheses,
+ r#"fn f(call: fn(usize), arg: usize) { $0(call)(arg); }"#,
+ r#"fn f(call: fn(usize), arg: usize) { call(arg); }"#,
+ );
+ check_assist(
+ remove_parentheses,
+ r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { $0(call)(arg); }"#,
+ r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { call(arg); }"#,
+ );
+
+ // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union.
+ check_assist_not_applicable(
+ remove_parentheses,
+ r#"
+struct Foo<T> {
+ t: T,
+}
+
+impl Foo<fn(usize)> {
+ fn foo(&self, arg: usize) {
+ $0(self.t)(arg);
+ }
+}"#,
+ );
+ }
}
diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs
index 9131cd2f17..28089ffb37 100644
--- a/crates/syntax/src/ast/prec.rs
+++ b/crates/syntax/src/ast/prec.rs
@@ -27,6 +27,14 @@ impl Expr {
}
fn needs_parens_in_expr(&self, parent: &Expr) -> bool {
+ // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union
+ // (e.g. `(a.f)()`).
+ let is_parent_call_expr = matches!(parent, ast::Expr::CallExpr(_));
+ let is_field_expr = matches!(self, ast::Expr::FieldExpr(_));
+ if is_parent_call_expr && is_field_expr {
+ return true;
+ }
+
// Special-case block weirdness
if parent.child_is_followed_by_a_block() {
use Expr::*;