about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-12-08 18:44:03 +0000
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-12-08 18:46:30 +0000
commit8d42439a7d5c3edbb0ef6d1398436944ed662111 (patch)
tree71f9da9ec5ce128cf48a11deea442d592114352a
parent2870b01ec0d434261b14726c2b2671001b817772 (diff)
downloadrust-8d42439a7d5c3edbb0ef6d1398436944ed662111.tar.gz
rust-8d42439a7d5c3edbb0ef6d1398436944ed662111.zip
Move precedence handling to `crates/syntax`
-rw-r--r--crates/ide-assists/src/handlers/remove_parentheses.rs94
-rw-r--r--crates/syntax/src/ast.rs1
-rw-r--r--crates/syntax/src/ast/prec.rs115
3 files changed, 117 insertions, 93 deletions
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 <https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296>
-        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<ExprPrecedence> {
+        // Copied from <https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296>
+        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<BinOpPresedence> {
+        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)
+    }
+}