Skip to content

Commit 629baf2

Browse files
committed
Remove syntax editing from parenthesis computation
1 parent ff7de58 commit 629baf2

6 files changed

Lines changed: 50 additions & 87 deletions

File tree

‎src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs‎

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ use ide_db::{
66
syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
77
};
88
use syntax::{
9-
ast::{self, syntax_factory::SyntaxFactory,AstNode,Expr::BinExpr,HasArgList},
9+
ast::{
10+
self,
11+
prec::{precedence,ExprPrecedence},
12+
syntax_factory::SyntaxFactory,
13+
AstNode,
14+
Expr::BinExpr,
15+
HasArgList,
16+
},
1017
syntax_editor::{Position,SyntaxEditor},
11-
SyntaxKind,SyntaxNode,T,
18+
SyntaxKind,T,
1219
};
1320

1421
usecrate::{utils::invert_boolean_expression,AssistContext,AssistId,AssistKind,Assists};
@@ -52,9 +59,9 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
5259
}
5360

5461
let op = bin_expr.op_kind()?;
55-
let inv_token = match op {
56-
ast::BinaryOp::LogicOp(ast::LogicOp::And) => SyntaxKind::PIPE2,
57-
ast::BinaryOp::LogicOp(ast::LogicOp::Or) => SyntaxKind::AMP2,
62+
let(inv_token, prec) = match op {
63+
ast::BinaryOp::LogicOp(ast::LogicOp::And) => (SyntaxKind::PIPE2,ExprPrecedence::LOr),
64+
ast::BinaryOp::LogicOp(ast::LogicOp::Or) => (SyntaxKind::AMP2,ExprPrecedence::LAnd),
5865
_ => returnNone,
5966
};
6067

@@ -65,33 +72,33 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
6572
editor.replace(demorganed.op_token()?, make.token(inv_token));
6673

6774
letmut exprs = VecDeque::from([
68-
(bin_expr.lhs()?, demorganed.lhs()?),
69-
(bin_expr.rhs()?, demorganed.rhs()?),
75+
(bin_expr.lhs()?, demorganed.lhs()?, prec),
76+
(bin_expr.rhs()?, demorganed.rhs()?, prec),
7077
]);
7178

72-
whileletSome((expr,dm)) = exprs.pop_front(){
79+
whileletSome((expr,demorganed, prec)) = exprs.pop_front(){
7380
ifletBinExpr(bin_expr) = &expr {
74-
ifletBinExpr(cbin_expr) = &dm{
81+
ifletBinExpr(cbin_expr) = &demorganed{
7582
if op == bin_expr.op_kind()? {
7683
editor.replace(cbin_expr.op_token()?, make.token(inv_token));
77-
exprs.push_back((bin_expr.lhs()?, cbin_expr.lhs()?));
78-
exprs.push_back((bin_expr.rhs()?, cbin_expr.rhs()?));
84+
exprs.push_back((bin_expr.lhs()?, cbin_expr.lhs()?, prec));
85+
exprs.push_back((bin_expr.rhs()?, cbin_expr.rhs()?, prec));
7986
}else{
8087
letmut inv = invert_boolean_expression(&make, expr);
81-
ifneeds_parens_in_place_of(&inv,&dm.syntax().parent()?,&dm){
88+
ifprecedence(&inv).needs_parentheses_in(prec){
8289
inv = make.expr_paren(inv).into();
8390
}
84-
editor.replace(dm.syntax(), inv.syntax());
91+
editor.replace(demorganed.syntax(), inv.syntax());
8592
}
8693
}else{
8794
returnNone;
8895
}
8996
}else{
90-
letmut inv = invert_boolean_expression(&make,dm.clone());
91-
ifneeds_parens_in_place_of(&inv,&dm.syntax().parent()?,&dm){
97+
letmut inv = invert_boolean_expression(&make,demorganed.clone());
98+
ifprecedence(&inv).needs_parentheses_in(prec){
9299
inv = make.expr_paren(inv).into();
93100
}
94-
editor.replace(dm.syntax(), inv.syntax());
101+
editor.replace(demorganed.syntax(), inv.syntax());
95102
}
96103
}
97104

@@ -121,7 +128,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
121128
let parent = neg_expr.syntax().parent();
122129
editor = builder.make_editor(neg_expr.syntax());
123130

124-
if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)){
131+
if parent.is_some_and(|parent| demorganed.needs_parens_in(&parent)){
125132
cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
126133
editor.replace(neg_expr.syntax(), make.expr_paren(demorganed).syntax());
127134
}else{
@@ -271,30 +278,6 @@ fn add_bang_paren(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr {
271278
make.expr_prefix(T![!], make.expr_paren(expr).into()).into()
272279
}
273280

274-
fnneeds_parens_in_place_of(
275-
this:&ast::Expr,
276-
parent:&SyntaxNode,
277-
in_place_of:&ast::Expr,
278-
) -> bool{
279-
assert_eq!(Some(parent), in_place_of.syntax().parent().as_ref());
280-
281-
let child_idx = parent
282-
.children()
283-
.enumerate()
284-
.find_map(|(i, it)| if&it == in_place_of.syntax(){Some(i)}else{None})
285-
.unwrap();
286-
let parent = parent.clone_subtree();
287-
let subtree_place = parent.children().nth(child_idx).unwrap();
288-
289-
letmut editor = SyntaxEditor::new(parent);
290-
editor.replace(subtree_place, this.syntax());
291-
let edit = editor.finish();
292-
293-
let replaced = edit.new_root().children().nth(child_idx).unwrap();
294-
let replaced = ast::Expr::cast(replaced).unwrap();
295-
replaced.needs_parens_in(edit.new_root().clone())
296-
}
297-
298281
#[cfg(test)]
299282
mod tests {
300283
usesuper::*;

‎src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_local_variable.rs‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,7 @@ use ide_db::{
55
EditionedFileId,RootDatabase,
66
};
77
use syntax::{
8-
ast::{
9-
self,
10-
prec::{precedence,ExprPrecedence},
11-
AstNode,AstToken,HasName,
12-
},
8+
ast::{self,AstNode,AstToken,HasName},
139
SyntaxElement,TextRange,
1410
};
1511

@@ -77,22 +73,12 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
7773
}
7874
let usage_node =
7975
name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind()));
80-
let usage_parent_option =
81-
usage_node.and_then(|it| it.parent()).and_then(ast::Expr::cast);
76+
let usage_parent_option = usage_node.and_then(|it| it.parent());
8277
let usage_parent = match usage_parent_option {
8378
Some(u) => u,
8479
None => returnSome((range, name_ref,false)),
8580
};
86-
let initializer = precedence(&initializer_expr);
87-
let parent = precedence(&usage_parent);
88-
Some((
89-
range,
90-
name_ref,
91-
parent != ExprPrecedence::Unambiguous
92-
&& initializer < parent
93-
// initializer == ExprPrecedence::Prefix -> parent != ExprPrecedence::Jump
94-
&& (initializer != ExprPrecedence::Prefix || parent != ExprPrecedence::Jump),
95-
))
81+
Some((range, name_ref, initializer_expr.needs_parens_in(&usage_parent)))
9682
})
9783
.collect::<Option<Vec<_>>>()?;
9884

‎src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
3434
let expr = parens.expr()?;
3535

3636
let parent = parens.syntax().parent()?;
37-
if expr.needs_parens_in(parent){
37+
if expr.needs_parens_in(&parent){
3838
returnNone;
3939
}
4040

‎src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs‎

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ide_db::imports::insert_use::ImportScope;
22
use syntax::{
3-
ast::{self,make,AstNode,HasArgList},
3+
ast::{self,prec::ExprPrecedence,AstNode,HasArgList},
44
TextRange,
55
};
66

@@ -55,7 +55,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
5555
TextRange::new(path.syntax().text_range().start(), l_paren.text_range().end());
5656

5757
// Parens around `expr` if needed
58-
let parens = needs_parens_as_receiver(&first_arg).then(|| {
58+
let parens = first_arg.precedence().needs_parentheses_in(ExprPrecedence::Postfix).then(|| {
5959
let range = first_arg.syntax().text_range();
6060
(range.start(), range.end())
6161
});
@@ -124,24 +124,6 @@ fn add_import(
124124
}
125125
}
126126

127-
fnneeds_parens_as_receiver(expr:&ast::Expr) -> bool{
128-
// Make `(expr).dummy()`
129-
let dummy_call = make::expr_method_call(
130-
make::expr_paren(expr.clone()),
131-
make::name_ref("dummy"),
132-
make::arg_list([]),
133-
);
134-
135-
// Get the `expr` clone with the right parent back
136-
// (unreachable!s are fine since we've just constructed the expression)
137-
let ast::Expr::MethodCallExpr(call) = &dummy_call else{unreachable!()};
138-
letSome(receiver) = call.receiver()else{unreachable!()};
139-
let ast::Expr::ParenExpr(parens) = receiver else{unreachable!()};
140-
letSome(expr) = parens.expr()else{unreachable!()};
141-
142-
expr.needs_parens_in(dummy_call.syntax().clone())
143-
}
144-
145127
#[cfg(test)]
146128
mod tests {
147129
usecrate::tests::{check_assist, check_assist_not_applicable};

‎src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,15 +258,12 @@ fn mode_and_needs_parens_for_adjustment_hints(
258258
fnneeds_parens_for_adjustment_hints(expr:&ast::Expr,postfix:bool) -> (bool,bool){
259259
let prec = expr.precedence();
260260
if postfix {
261-
// postfix ops have higher precedence than any other operator, so we need to wrap
262-
// any inner expression that is below
263-
let needs_inner_parens = prec < ExprPrecedence::Postfix;
261+
let needs_inner_parens = prec.needs_parentheses_in(ExprPrecedence::Postfix);
264262
// given we are the higher precedence, no parent expression will have stronger requirements
265263
let needs_outer_parens = false;
266264
(needs_outer_parens, needs_inner_parens)
267265
}else{
268-
// We need to wrap all binary like things, thats everything below prefix except for jumps
269-
let needs_inner_parens = prec < ExprPrecedence::Prefix && prec != ExprPrecedence::Jump;
266+
let needs_inner_parens = prec.needs_parentheses_in(ExprPrecedence::Prefix);
270267
let parent = expr
271268
.syntax()
272269
.parent()
@@ -278,8 +275,8 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool,
278275

279276
// if we have no parent, we don't need outer parens to disambiguate
280277
// otherwise anything with higher precedence than what we insert needs to wrap us
281-
let needs_outer_parens =
282-
parent.is_some_and(|parent_prec| parent_prec > ExprPrecedence::Prefix);
278+
let needs_outer_parens = parent
279+
.is_some_and(|parent_prec| ExprPrecedence::Prefix.needs_parentheses_in(parent_prec));
283280
(needs_outer_parens, needs_inner_parens)
284281
}
285282
}

‎src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ pub enum ExprPrecedence {
4141
Unambiguous,
4242
}
4343

44+
implExprPrecedence{
45+
pubfnneeds_parentheses_in(self,other:ExprPrecedence) -> bool{
46+
match other {
47+
ExprPrecedence::Unambiguous => false,
48+
// postfix ops have higher precedence than any other operator, so we need to wrap
49+
// any inner expression that is below
50+
ExprPrecedence::Postfix => self < ExprPrecedence::Postfix,
51+
// We need to wrap all binary like things, thats everything below prefix except for
52+
// jumps (as those are prefix operations as well)
53+
ExprPrecedence::Prefix => ExprPrecedence::Jump < self && self < ExprPrecedence::Prefix,
54+
parent => self <= parent,
55+
}
56+
}
57+
}
58+
4459
#[derive(PartialEq,Debug)]
4560
pubenumFixity{
4661
/// The operator is left-associative
@@ -137,7 +152,7 @@ impl Expr {
137152
// - https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296
138153

139154
/// Returns `true` if `self` would need to be wrapped in parentheses given that its parent is `parent`.
140-
pubfnneeds_parens_in(&self,parent:SyntaxNode) -> bool{
155+
pubfnneeds_parens_in(&self,parent:&SyntaxNode) -> bool{
141156
match_ast!{
142157
match parent {
143158
ast::Expr(e) => self.needs_parens_in_expr(&e),

0 commit comments

Comments
 (0)