diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs index de79962dd8e..30e9609f7a7 100644 --- a/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -30,8 +30,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) -> let expr = parens.expr()?; let parent = ast::Expr::cast(parens.syntax().parent()?); - let is_ok_to_remove = - parent.map_or(true, |p| ExprPrecedence::of(&expr) >= ExprPrecedence::of(&p)); + let is_ok_to_remove = expr.precedence() >= parent.as_ref().and_then(ast::Expr::precedence); if !is_ok_to_remove { return None; } @@ -60,97 +59,6 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) -> ) } -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub enum ExprPrecedence { - // N.B.: Order is important - /// Precedence is unknown - Dummy, - Closure, - Jump, - Range, - Bin(BinOpPresedence), - Prefix, - Postfix, - Paren, -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub enum BinOpPresedence { - // N.B.: Order is important - /// `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `&=` - Assign, - /// `||` - LOr, - /// `&&` - LAnd, - /// `<`, `<=`, `>`, `>=`, `==` and `!=` - Cmp, - /// `|` - BitOr, - /// `^` - BitXor, - /// `&` - BitAnd, - /// `<<` and `>>` - Shift, - /// `+` and `-` - Add, - /// `*`, `/` and `%` - Mul, - /// `as` - As, -} - -impl ExprPrecedence { - pub fn of(expr: &ast::Expr) -> Self { - // Copied from - use ast::Expr::*; - - match expr { - ClosureExpr(_) => Self::Closure, - - ContinueExpr(_) | ReturnExpr(_) | YieldExpr(_) | BreakExpr(_) => Self::Jump, - - RangeExpr(_) => Self::Range, - - BinExpr(bin_expr) => bin_expr - .op_kind() - .map(|op| match op { - ast::BinaryOp::LogicOp(op) => match op { - ast::LogicOp::And => BinOpPresedence::LAnd, - ast::LogicOp::Or => BinOpPresedence::LOr, - }, - ast::BinaryOp::ArithOp(op) => match op { - ast::ArithOp::Add => BinOpPresedence::Add, - ast::ArithOp::Mul => BinOpPresedence::Mul, - ast::ArithOp::Sub => BinOpPresedence::Add, - ast::ArithOp::Div => BinOpPresedence::Mul, - ast::ArithOp::Rem => BinOpPresedence::Mul, - ast::ArithOp::Shl => BinOpPresedence::Shift, - ast::ArithOp::Shr => BinOpPresedence::Shift, - ast::ArithOp::BitXor => BinOpPresedence::BitXor, - ast::ArithOp::BitOr => BinOpPresedence::BitOr, - ast::ArithOp::BitAnd => BinOpPresedence::BitAnd, - }, - ast::BinaryOp::CmpOp(_) => BinOpPresedence::Cmp, - ast::BinaryOp::Assignment { .. } => BinOpPresedence::Assign, - }) - .map(Self::Bin) - .unwrap_or(Self::Dummy), - CastExpr(_) => Self::Bin(BinOpPresedence::As), - - BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => Self::Prefix, - - AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | FieldExpr(_) | IndexExpr(_) - | TryExpr(_) | MacroExpr(_) => Self::Postfix, - - ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_) | IfExpr(_) - | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_) | BlockExpr(_) - | RecordExpr(_) | UnderscoreExpr(_) => Self::Paren, - } - } -} - #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 4aa64d0d6e8..10c04575833 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -9,6 +9,7 @@ mod operators; pub mod edit; pub mod edit_in_place; pub mod make; +pub mod prec; use std::marker::PhantomData; diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs new file mode 100644 index 00000000000..6253c4dc3e7 --- /dev/null +++ b/crates/syntax/src/ast/prec.rs @@ -0,0 +1,115 @@ +//! Precedence representation. + +use crate::ast::{self, BinExpr, Expr}; + +/// Precedence of an expression. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub enum ExprPrecedence { + // N.B.: Order is important + Closure, + Jump, + Range, + Bin(BinOpPresedence), + Prefix, + Postfix, + Paren, +} + +/// Precedence of a binary operator. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub enum BinOpPresedence { + // N.B.: Order is important + /// `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `&=` + Assign, + /// `||` + LOr, + /// `&&` + LAnd, + /// `<`, `<=`, `>`, `>=`, `==` and `!=` + Cmp, + /// `|` + BitOr, + /// `^` + BitXor, + /// `&` + BitAnd, + /// `<<` and `>>` + Shift, + /// `+` and `-` + Add, + /// `*`, `/` and `%` + Mul, + /// `as` + As, +} + +impl Expr { + /// Returns precedence of this expression. + /// Usefull to preserve semantics in assists. + /// + /// Returns `None` if this is a [`BinExpr`] and its [`op_kind`] returns `None`. + /// + /// [`op_kind`]: BinExpr::op_kind + /// [`BinExpr`]: Expr::BinExpr + pub fn precedence(&self) -> Option { + // Copied from + use Expr::*; + + let prec = match self { + ClosureExpr(_) => ExprPrecedence::Closure, + + ContinueExpr(_) | ReturnExpr(_) | YieldExpr(_) | BreakExpr(_) => ExprPrecedence::Jump, + + RangeExpr(_) => ExprPrecedence::Range, + + BinExpr(bin_expr) => return bin_expr.precedence().map(ExprPrecedence::Bin), + CastExpr(_) => ExprPrecedence::Bin(BinOpPresedence::As), + + BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => ExprPrecedence::Prefix, + + AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | FieldExpr(_) | IndexExpr(_) + | TryExpr(_) | MacroExpr(_) => ExprPrecedence::Postfix, + + ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_) | IfExpr(_) + | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_) | BlockExpr(_) + | RecordExpr(_) | UnderscoreExpr(_) => ExprPrecedence::Paren, + }; + + Some(prec) + } +} + +impl BinExpr { + /// Returns precedence of this binary expression. + /// Usefull to preserve semantics in assists. + /// + /// Returns `None` if [`op_kind`] returns `None`. + /// + /// [`op_kind`]: BinExpr::op_kind + pub fn precedence(&self) -> Option { + use ast::{ArithOp::*, BinaryOp::*, LogicOp::*}; + + let prec = match self.op_kind()? { + LogicOp(op) => match op { + And => BinOpPresedence::LAnd, + Or => BinOpPresedence::LOr, + }, + ArithOp(op) => match op { + Add => BinOpPresedence::Add, + Mul => BinOpPresedence::Mul, + Sub => BinOpPresedence::Add, + Div => BinOpPresedence::Mul, + Rem => BinOpPresedence::Mul, + Shl => BinOpPresedence::Shift, + Shr => BinOpPresedence::Shift, + BitXor => BinOpPresedence::BitXor, + BitOr => BinOpPresedence::BitOr, + BitAnd => BinOpPresedence::BitAnd, + }, + CmpOp(_) => BinOpPresedence::Cmp, + Assignment { .. } => BinOpPresedence::Assign, + }; + + Some(prec) + } +}