@@ -28,7 +28,13 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
28
28
return None ;
29
29
}
30
30
31
- // FIXME: check that precedence is right
31
+ let expr = parens. expr ( ) ?;
32
+ let parent = ast:: Expr :: cast ( parens. syntax ( ) . parent ( ) ?) ;
33
+ let is_ok_to_remove =
34
+ parent. map_or ( true , |p| ExprPrecedence :: of ( & expr) >= ExprPrecedence :: of ( & p) ) ;
35
+ if !is_ok_to_remove {
36
+ return None ;
37
+ }
32
38
33
39
let delete_from_l = l_paren. text_range ( ) . start ( ) ;
34
40
let delete_to_l = match l_paren. next_token ( ) {
@@ -54,6 +60,97 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
54
60
)
55
61
}
56
62
63
+ #[ derive( Debug , Copy , Clone , Ord , PartialOrd , Eq , PartialEq ) ]
64
+ pub enum ExprPrecedence {
65
+ // N.B.: Order is important
66
+ /// Precedence is unknown
67
+ Dummy ,
68
+ Closure ,
69
+ Jump ,
70
+ Range ,
71
+ Bin ( BinOpPresedence ) ,
72
+ Prefix ,
73
+ Postfix ,
74
+ Paren ,
75
+ }
76
+
77
+ #[ derive( Debug , Copy , Clone , Ord , PartialOrd , Eq , PartialEq ) ]
78
+ pub enum BinOpPresedence {
79
+ // N.B.: Order is important
80
+ /// `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `&=`
81
+ Assign ,
82
+ /// `||`
83
+ LOr ,
84
+ /// `&&`
85
+ LAnd ,
86
+ /// `<`, `<=`, `>`, `>=`, `==` and `!=`
87
+ Cmp ,
88
+ /// `|`
89
+ BitOr ,
90
+ /// `^`
91
+ BitXor ,
92
+ /// `&`
93
+ BitAnd ,
94
+ /// `<<` and `>>`
95
+ Shift ,
96
+ /// `+` and `-`
97
+ Add ,
98
+ /// `*`, `/` and `%`
99
+ Mul ,
100
+ /// `as`
101
+ As ,
102
+ }
103
+
104
+ impl ExprPrecedence {
105
+ pub fn of ( expr : & ast:: Expr ) -> Self {
106
+ // Copied from <https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296>
107
+ use ast:: Expr :: * ;
108
+
109
+ match expr {
110
+ ClosureExpr ( _) => Self :: Closure ,
111
+
112
+ ContinueExpr ( _) | ReturnExpr ( _) | YieldExpr ( _) | BreakExpr ( _) => Self :: Jump ,
113
+
114
+ RangeExpr ( _) => Self :: Range ,
115
+
116
+ BinExpr ( bin_expr) => bin_expr
117
+ . op_kind ( )
118
+ . map ( |op| match op {
119
+ ast:: BinaryOp :: LogicOp ( op) => match op {
120
+ ast:: LogicOp :: And => BinOpPresedence :: LAnd ,
121
+ ast:: LogicOp :: Or => BinOpPresedence :: LOr ,
122
+ } ,
123
+ ast:: BinaryOp :: ArithOp ( op) => match op {
124
+ ast:: ArithOp :: Add => BinOpPresedence :: Add ,
125
+ ast:: ArithOp :: Mul => BinOpPresedence :: Mul ,
126
+ ast:: ArithOp :: Sub => BinOpPresedence :: Add ,
127
+ ast:: ArithOp :: Div => BinOpPresedence :: Mul ,
128
+ ast:: ArithOp :: Rem => BinOpPresedence :: Mul ,
129
+ ast:: ArithOp :: Shl => BinOpPresedence :: Shift ,
130
+ ast:: ArithOp :: Shr => BinOpPresedence :: Shift ,
131
+ ast:: ArithOp :: BitXor => BinOpPresedence :: BitXor ,
132
+ ast:: ArithOp :: BitOr => BinOpPresedence :: BitOr ,
133
+ ast:: ArithOp :: BitAnd => BinOpPresedence :: BitAnd ,
134
+ } ,
135
+ ast:: BinaryOp :: CmpOp ( _) => BinOpPresedence :: Cmp ,
136
+ ast:: BinaryOp :: Assignment { .. } => BinOpPresedence :: Assign ,
137
+ } )
138
+ . map ( Self :: Bin )
139
+ . unwrap_or ( Self :: Dummy ) ,
140
+ CastExpr ( _) => Self :: Bin ( BinOpPresedence :: As ) ,
141
+
142
+ BoxExpr ( _) | RefExpr ( _) | LetExpr ( _) | PrefixExpr ( _) => Self :: Prefix ,
143
+
144
+ AwaitExpr ( _) | CallExpr ( _) | MethodCallExpr ( _) | FieldExpr ( _) | IndexExpr ( _)
145
+ | TryExpr ( _) | MacroExpr ( _) => Self :: Postfix ,
146
+
147
+ ArrayExpr ( _) | TupleExpr ( _) | Literal ( _) | PathExpr ( _) | ParenExpr ( _) | IfExpr ( _)
148
+ | WhileExpr ( _) | ForExpr ( _) | LoopExpr ( _) | MatchExpr ( _) | BlockExpr ( _)
149
+ | RecordExpr ( _) | UnderscoreExpr ( _) => Self :: Paren ,
150
+ }
151
+ }
152
+ }
153
+
57
154
#[ cfg( test) ]
58
155
mod tests {
59
156
use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -68,14 +165,29 @@ mod tests {
68
165
check_assist ( remove_parentheses, r#"fn f() { (2$0) + 2; }"# , r#"fn f() { 2 + 2; }"# ) ;
69
166
}
70
167
71
- // We should not permit assist here and yet
72
168
#[ test]
73
- fn remove_parens_wrong ( ) {
169
+ fn remove_parens_precedence ( ) {
74
170
check_assist (
75
171
remove_parentheses,
76
- r#"fn f() { $0(2 + 2) * 8 ; }"# ,
77
- r#"fn f() { 2 + 2 * 8 ; }"# ,
172
+ r#"fn f() { $0(2 * 3) + 1 ; }"# ,
173
+ r#"fn f() { 2 * 3 + 1 ; }"# ,
78
174
) ;
175
+ check_assist ( remove_parentheses, r#"fn f() { ( $0(2) ); }"# , r#"fn f() { ( 2 ); }"# ) ;
176
+ check_assist ( remove_parentheses, r#"fn f() { $0(2?)?; }"# , r#"fn f() { 2??; }"# ) ;
177
+ check_assist ( remove_parentheses, r#"fn f() { f(($02 + 2)); }"# , r#"fn f() { f(2 + 2); }"# ) ;
178
+ check_assist (
179
+ remove_parentheses,
180
+ r#"fn f() { (1<2)&&$0(3>4); }"# ,
181
+ r#"fn f() { (1<2)&&3>4; }"# ,
182
+ ) ;
183
+ }
184
+
185
+ #[ test]
186
+ fn remove_parens_doesnt_apply_precedence ( ) {
187
+ check_assist_not_applicable ( remove_parentheses, r#"fn f() { $0(2 + 2) * 8; }"# ) ;
188
+ check_assist_not_applicable ( remove_parentheses, r#"fn f() { $0(2 + 2).f(); }"# ) ;
189
+ check_assist_not_applicable ( remove_parentheses, r#"fn f() { $0(2 + 2).await; }"# ) ;
190
+ check_assist_not_applicable ( remove_parentheses, r#"fn f() { $0!(2..2); }"# ) ;
79
191
}
80
192
81
193
#[ test]
0 commit comments