about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGiga Bowser <45986823+Giga-Bowser@users.noreply.github.com>2024-12-18 11:33:35 -0500
committerGiga Bowser <45986823+Giga-Bowser@users.noreply.github.com>2025-01-06 15:58:39 -0600
commit396b56fd5237e7fe76565882fa6c4a59e5374c5a (patch)
tree15392382ecc05142d72251db956530dbb8839d5d
parentcd803805b79bf7324a7dba73b129568069fac343 (diff)
downloadrust-396b56fd5237e7fe76565882fa6c4a59e5374c5a.tar.gz
rust-396b56fd5237e7fe76565882fa6c4a59e5374c5a.zip
internal: Add some expr constructors to `SyntaxFactory`
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs23
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs154
2 files changed, 175 insertions, 2 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
index 9466755576b..93faeb40c32 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
@@ -10,7 +10,7 @@ use crate::{
         FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree,
     },
     AstToken,
-    SyntaxKind::*,
+    SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, T,
 };
 
@@ -50,6 +50,27 @@ impl From<ast::IfExpr> for ElseBranch {
     }
 }
 
+impl AstNode for ElseBranch {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        ast::BlockExpr::can_cast(kind) || ast::IfExpr::can_cast(kind)
+    }
+
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if let Some(block_expr) = ast::BlockExpr::cast(syntax.clone()) {
+            Some(Self::Block(block_expr))
+        } else {
+            ast::IfExpr::cast(syntax).map(Self::IfExpr)
+        }
+    }
+
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            ElseBranch::Block(block_expr) => block_expr.syntax(),
+            ElseBranch::IfExpr(if_expr) => if_expr.syntax(),
+        }
+    }
+}
+
 impl ast::IfExpr {
     pub fn condition(&self) -> Option<ast::Expr> {
         // If the condition is a BlockExpr, check if the then body is missing.
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 253791bfc02..39320cf504c 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -167,6 +167,19 @@ impl SyntaxFactory {
         ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
     }
 
+    pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
+        let (fields, input) = iterator_input(fields);
+        let ast = make::expr_tuple(fields).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
         let ast::Expr::BinExpr(ast) =
             make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
@@ -184,6 +197,10 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_literal(&self, text: &str) -> ast::Literal {
+        make::expr_literal(text).clone_for_update()
+    }
+
     pub fn expr_path(&self, path: ast::Path) -> ast::Expr {
         let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else {
             unreachable!()
@@ -198,6 +215,18 @@ impl SyntaxFactory {
         ast.into()
     }
 
+    pub fn expr_prefix(&self, op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr {
+        let ast = make::expr_prefix(op, expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr {
         let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update()
         else {
@@ -229,6 +258,125 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_if(
+        &self,
+        condition: ast::Expr,
+        then_branch: ast::BlockExpr,
+        else_branch: Option<ast::ElseBranch>,
+    ) -> ast::IfExpr {
+        let ast = make::expr_if(condition.clone(), then_branch.clone(), else_branch.clone())
+            .clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
+            builder.map_node(
+                then_branch.syntax().clone(),
+                ast.then_branch().unwrap().syntax().clone(),
+            );
+
+            if let Some(else_branch) = else_branch {
+                builder.map_node(
+                    else_branch.syntax().clone(),
+                    ast.else_branch().unwrap().syntax().clone(),
+                );
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
+        let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_stmt(&self, expr: ast::Expr) -> ast::ExprStmt {
+        let ast = make::expr_stmt(expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn expr_match(&self, expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr {
+        let ast = make::expr_match(expr.clone(), match_arm_list.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.map_node(
+                match_arm_list.syntax().clone(),
+                ast.match_arm_list().unwrap().syntax().clone(),
+            );
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_arm(
+        &self,
+        pat: ast::Pat,
+        guard: Option<ast::MatchGuard>,
+        expr: ast::Expr,
+    ) -> ast::MatchArm {
+        let ast = make::match_arm(pat.clone(), guard.clone(), expr.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
+            if let Some(guard) = guard {
+                builder.map_node(guard.syntax().clone(), ast.guard().unwrap().syntax().clone());
+            }
+            builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_guard(&self, condition: ast::Expr) -> ast::MatchGuard {
+        let ast = make::match_guard(condition.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
+    pub fn match_arm_list(
+        &self,
+        match_arms: impl IntoIterator<Item = ast::MatchArm>,
+    ) -> ast::MatchArmList {
+        let (match_arms, input) = iterator_input(match_arms);
+        let ast = make::match_arm_list(match_arms).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_children(input.into_iter(), ast.arms().map(|it| it.syntax().clone()));
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn let_stmt(
         &self,
         pattern: ast::Pat,
@@ -572,13 +720,17 @@ impl SyntaxFactory {
         make::token(kind)
     }
 
-    pub fn whitespace(&self, text: &str) -> ast::SyntaxToken {
+    pub fn whitespace(&self, text: &str) -> SyntaxToken {
         make::tokens::whitespace(text)
     }
 }
 
 // `ext` constructors
 impl SyntaxFactory {
+    pub fn expr_unit(&self) -> ast::Expr {
+        self.expr_tuple([]).into()
+    }
+
     pub fn ident_path(&self, ident: &str) -> ast::Path {
         self.path_unqualified(self.path_segment(self.name_ref(ident)))
     }