@@ -28,7 +28,13 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
2828 return None ;
2929 }
3030
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+ }
3238
3339 let delete_from_l = l_paren. text_range ( ) . start ( ) ;
3440 let delete_to_l = match l_paren. next_token ( ) {
@@ -54,6 +60,97 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
5460 )
5561}
5662
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+
57154#[ cfg( test) ]
58155mod tests {
59156 use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -68,14 +165,29 @@ mod tests {
68165 check_assist ( remove_parentheses, r#"fn f() { (2$0) + 2; }"# , r#"fn f() { 2 + 2; }"# ) ;
69166 }
70167
71- // We should not permit assist here and yet
72168 #[ test]
73- fn remove_parens_wrong ( ) {
169+ fn remove_parens_precedence ( ) {
74170 check_assist (
75171 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 ; }"# ,
78174 ) ;
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); }"# ) ;
79191 }
80192
81193 #[ test]
0 commit comments