Unnamed repository; edit this file 'description' to name the repository.
move SyntaxFactory inside SyntaxEditor
bit-aloo 6 weeks ago
parent 17d028e · commit 8c8932f
-rw-r--r--crates/syntax/src/ast/edit.rs7
-rw-r--r--crates/syntax/src/ast/syntax_factory.rs10
-rw-r--r--crates/syntax/src/syntax_editor.rs88
-rw-r--r--crates/syntax/src/syntax_editor/edit_algo.rs3
-rw-r--r--crates/syntax/src/syntax_editor/edits.rs34
5 files changed, 61 insertions, 81 deletions
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 567bd09025..ae1293fb2f 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -202,7 +202,6 @@ impl ast::IdentPat {
&self,
pat: Option<ast::Pat>,
syntax_editor: &mut SyntaxEditor,
- syntax_factory: &SyntaxFactory,
) -> ast::IdentPat {
match pat {
None => {
@@ -234,9 +233,9 @@ impl ast::IdentPat {
// Don't have an `@`, should have a name
let name = self.name().unwrap();
let elements = vec![
- syntax_factory.whitespace(" ").into(),
- syntax_factory.token(T![@]).into(),
- syntax_factory.whitespace(" ").into(),
+ syntax_editor.make().whitespace(" ").into(),
+ syntax_editor.make().token(T![@]).into(),
+ syntax_editor.make().whitespace(" ").into(),
pat.syntax().clone().into(),
];
diff --git a/crates/syntax/src/ast/syntax_factory.rs b/crates/syntax/src/ast/syntax_factory.rs
index f3ae7544cc..9369a4e700 100644
--- a/crates/syntax/src/ast/syntax_factory.rs
+++ b/crates/syntax/src/ast/syntax_factory.rs
@@ -12,6 +12,7 @@ use std::cell::{RefCell, RefMut};
use crate::syntax_editor::SyntaxMapping;
+#[derive(Debug)]
pub struct SyntaxFactory {
// Stored in a refcell so that the factory methods can be &self
mappings: Option<RefCell<SyntaxMapping>>,
@@ -19,7 +20,7 @@ pub struct SyntaxFactory {
impl SyntaxFactory {
/// Creates a new [`SyntaxFactory`], generating mappings between input nodes and generated nodes.
- pub fn with_mappings() -> Self {
+ pub(crate) fn with_mappings() -> Self {
Self { mappings: Some(RefCell::new(SyntaxMapping::default())) }
}
@@ -28,13 +29,8 @@ impl SyntaxFactory {
Self { mappings: None }
}
- /// Gets all of the tracked syntax mappings, if any.
- pub fn finish_with_mappings(self) -> SyntaxMapping {
- self.mappings.unwrap_or_default().into_inner()
- }
-
/// Take all of the tracked syntax mappings, leaving `SyntaxMapping::default()` in its place, if any.
- pub fn take(&self) -> SyntaxMapping {
+ pub(crate) fn take(&self) -> SyntaxMapping {
self.mappings.as_ref().map(|mappings| mappings.take()).unwrap_or_default()
}
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index 8e4dc75d22..4c20dc7a15 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -30,8 +30,8 @@ pub use mapping::{SyntaxMapping, SyntaxMappingBuilder};
pub struct SyntaxEditor {
root: SyntaxNode,
changes: Vec<Change>,
- mappings: SyntaxMapping,
annotations: Vec<(SyntaxElement, SyntaxAnnotation)>,
+ make: SyntaxFactory,
}
impl SyntaxEditor {
@@ -51,8 +51,8 @@ impl SyntaxEditor {
let editor = Self {
root: root.clone(),
changes: Vec::new(),
- mappings: SyntaxMapping::default(),
annotations: Vec::new(),
+ make: SyntaxFactory::with_mappings(),
};
(editor, root)
@@ -68,6 +68,10 @@ impl SyntaxEditor {
(editor, T::cast(root).unwrap())
}
+ pub fn make(&self) -> &SyntaxFactory {
+ &self.make
+ }
+
pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) {
self.annotations.push((element.syntax_element(), annotation))
}
@@ -90,7 +94,9 @@ impl SyntaxEditor {
);
self.changes.append(&mut other.changes);
- self.mappings.merge(other.mappings);
+ if let Some(mut m) = self.make.mappings() {
+ m.merge(other.make.take());
+ }
self.annotations.append(&mut other.annotations);
}
@@ -104,28 +110,22 @@ impl SyntaxEditor {
self.changes.push(Change::InsertAll(position, elements))
}
- pub fn insert_with_whitespace(
- &mut self,
- position: Position,
- element: impl Element,
- factory: &SyntaxFactory,
- ) {
- self.insert_all_with_whitespace(position, vec![element.syntax_element()], factory)
+ pub fn insert_with_whitespace(&mut self, position: Position, element: impl Element) {
+ self.insert_all_with_whitespace(position, vec![element.syntax_element()])
}
pub fn insert_all_with_whitespace(
&mut self,
position: Position,
mut elements: Vec<SyntaxElement>,
- factory: &SyntaxFactory,
) {
if let Some(first) = elements.first()
- && let Some(ws) = ws_before(&position, first, factory)
+ && let Some(ws) = ws_before(&position, first, &self.make)
{
elements.insert(0, ws.into());
}
if let Some(last) = elements.last()
- && let Some(ws) = ws_after(&position, last, factory)
+ && let Some(ws) = ws_after(&position, last, &self.make)
{
elements.push(ws.into());
}
@@ -181,10 +181,6 @@ impl SyntaxEditor {
pub fn finish(self) -> SyntaxEdit {
edit_algo::apply_edits(self)
}
-
- pub fn add_mappings(&mut self, other: SyntaxMapping) {
- self.mappings.merge(other);
- }
}
/// Represents a completed [`SyntaxEditor`] operation.
@@ -538,7 +534,7 @@ mod tests {
use crate::{
AstNode,
- ast::{self, make, syntax_factory::SyntaxFactory},
+ ast::{self, make},
};
use super::*;
@@ -564,8 +560,6 @@ mod tests {
let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
- let make = SyntaxFactory::with_mappings();
-
let name = make::name("var_name");
let name_ref = make::name_ref("var_name").clone_for_update();
@@ -573,10 +567,11 @@ mod tests {
editor.add_annotation(name.syntax(), placeholder_snippet);
editor.add_annotation(name_ref.syntax(), placeholder_snippet);
- let new_block = make.block_expr(
- [make
+ let new_block = editor.make().block_expr(
+ [editor
+ .make()
.let_stmt(
- make.ident_pat(false, false, name.clone()).into(),
+ editor.make().ident_pat(false, false, name.clone()).into(),
None,
Some(to_replace.clone().into()),
)
@@ -586,7 +581,6 @@ mod tests {
editor.replace(to_replace.syntax(), name_ref.syntax());
editor.replace(to_wrap.syntax(), new_block.syntax());
- editor.add_mappings(make.finish_with_mappings());
let edit = editor.finish();
@@ -620,26 +614,29 @@ mod tests {
let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
- let make = SyntaxFactory::without_mappings();
editor.insert(
Position::first_child_of(root.stmt_list().unwrap().syntax()),
- make.let_stmt(
- make::ext::simple_ident_pat(make::name("first")).into(),
- None,
- Some(make::expr_literal("1").into()),
- )
- .syntax(),
+ editor
+ .make()
+ .let_stmt(
+ make::ext::simple_ident_pat(make::name("first")).into(),
+ None,
+ Some(make::expr_literal("1").into()),
+ )
+ .syntax(),
);
editor.insert(
Position::after(second_let.syntax()),
- make.let_stmt(
- make::ext::simple_ident_pat(make::name("third")).into(),
- None,
- Some(make::expr_literal("3").into()),
- )
- .syntax(),
+ editor
+ .make()
+ .let_stmt(
+ make::ext::simple_ident_pat(make::name("third")).into(),
+ None,
+ Some(make::expr_literal("3").into()),
+ )
+ .syntax(),
);
let edit = editor.finish();
@@ -675,17 +672,16 @@ mod tests {
root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
- let make = SyntaxFactory::with_mappings();
-
- let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
+ let new_block_expr =
+ editor.make().block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
- let first_let = make.let_stmt(
+ let first_let = editor.make().let_stmt(
make::ext::simple_ident_pat(make::name("first")).into(),
None,
Some(make::expr_literal("1").into()),
);
- let third_let = make.let_stmt(
+ let third_let = editor.make().let_stmt(
make::ext::simple_ident_pat(make::name("third")).into(),
None,
Some(make::expr_literal("3").into()),
@@ -697,7 +693,6 @@ mod tests {
);
editor.insert(Position::after(second_let.syntax()), third_let.syntax());
editor.replace(inner_block.syntax(), new_block_expr.syntax());
- editor.add_mappings(make.finish_with_mappings());
let edit = editor.finish();
@@ -727,11 +722,11 @@ mod tests {
let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
let inner_block = root;
- let make = SyntaxFactory::with_mappings();
- let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
+ let new_block_expr =
+ editor.make().block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
- let first_let = make.let_stmt(
+ let first_let = editor.make().let_stmt(
make::ext::simple_ident_pat(make::name("first")).into(),
None,
Some(make::expr_literal("1").into()),
@@ -742,7 +737,6 @@ mod tests {
first_let.syntax(),
);
editor.replace(inner_block.syntax(), new_block_expr.syntax());
- editor.add_mappings(make.finish_with_mappings());
let edit = editor.finish();
diff --git a/crates/syntax/src/syntax_editor/edit_algo.rs b/crates/syntax/src/syntax_editor/edit_algo.rs
index 78e7083f97..4e08daba7b 100644
--- a/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -35,7 +35,8 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
// - changed nodes become part of the changed node set (useful for the formatter to only change those parts)
// - Propagate annotations
- let SyntaxEditor { root, mut changes, mappings, annotations } = editor;
+ let SyntaxEditor { root, mut changes, annotations, make } = editor;
+ let mappings = make.take();
let mut node_depths = FxHashMap::<SyntaxNode, usize>::default();
let mut get_node_depth = |node: SyntaxNode| {
diff --git a/crates/syntax/src/syntax_editor/edits.rs b/crates/syntax/src/syntax_editor/edits.rs
index d741adb6e3..1718f1a51c 100644
--- a/crates/syntax/src/syntax_editor/edits.rs
+++ b/crates/syntax/src/syntax_editor/edits.rs
@@ -3,10 +3,7 @@
use crate::{
AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T,
algo::neighbor,
- ast::{
- self, AstNode, Fn, GenericParam, HasGenericParams, HasName, edit::IndentLevel, make,
- syntax_factory::SyntaxFactory,
- },
+ ast::{self, AstNode, Fn, GenericParam, HasGenericParams, HasName, edit::IndentLevel, make},
syntax_editor::{Position, SyntaxEditor},
};
@@ -16,20 +13,19 @@ pub trait GetOrCreateWhereClause: ast::HasGenericParams {
fn get_or_create_where_clause(
&self,
editor: &mut SyntaxEditor,
- make: &SyntaxFactory,
new_preds: impl Iterator<Item = ast::WherePred>,
) {
let existing = self.where_clause();
let all_preds: Vec<_> =
existing.iter().flat_map(|wc| wc.predicates()).chain(new_preds).collect();
- let new_where = make.where_clause(all_preds);
+ let new_where = editor.make().where_clause(all_preds);
if let Some(existing) = &existing {
editor.replace(existing.syntax(), new_where.syntax());
} else if let Some(pos) = self.where_clause_position() {
editor.insert_all(
pos,
- vec![make.whitespace(" ").into(), new_where.syntax().clone().into()],
+ vec![editor.make().whitespace(" ").into(), new_where.syntax().clone().into()],
);
}
}
@@ -178,7 +174,6 @@ impl SyntaxEditor {
}
fn get_or_insert_comma_after(editor: &mut SyntaxEditor, syntax: &SyntaxNode) -> SyntaxToken {
- let make = SyntaxFactory::without_mappings();
match syntax
.siblings_with_tokens(Direction::Next)
.filter_map(|it| it.into_token())
@@ -186,7 +181,7 @@ fn get_or_insert_comma_after(editor: &mut SyntaxEditor, syntax: &SyntaxNode) ->
{
Some(it) => it,
None => {
- let comma = make.token(T![,]);
+ let comma = editor.make().token(T![,]);
editor.insert(Position::after(syntax), &comma);
comma
}
@@ -233,15 +228,14 @@ impl ast::Impl {
pub fn get_or_create_assoc_item_list_with_editor(
&self,
editor: &mut SyntaxEditor,
- make: &SyntaxFactory,
) -> ast::AssocItemList {
if let Some(list) = self.assoc_item_list() {
list
} else {
- let list = make.assoc_item_list_empty();
+ let list = editor.make().assoc_item_list_empty();
editor.insert_all(
Position::last_child_of(self.syntax()),
- vec![make.whitespace(" ").into(), list.syntax().clone().into()],
+ vec![editor.make().whitespace(" ").into(), list.syntax().clone().into()],
);
list
}
@@ -250,7 +244,6 @@ impl ast::Impl {
impl ast::VariantList {
pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) {
- let make = SyntaxFactory::without_mappings();
let (indent, position) = match self.variants().last() {
Some(last_item) => (
IndentLevel::from_node(last_item.syntax()),
@@ -265,9 +258,9 @@ impl ast::VariantList {
},
};
let elements: Vec<SyntaxElement> = vec![
- make.whitespace(&format!("{}{indent}", "\n")).into(),
+ editor.make().whitespace(&format!("{}{indent}", "\n")).into(),
variant.syntax().clone().into(),
- make.token(T![,]).into(),
+ editor.make().token(T![,]).into(),
];
editor.insert_all(position, elements);
}
@@ -291,7 +284,6 @@ impl ast::Fn {
}
fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) -> Option<()> {
- let make = SyntaxFactory::without_mappings();
let l = node
.children_with_tokens()
.filter_map(|it| it.into_token())
@@ -306,11 +298,11 @@ fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) ->
match l.next_sibling_or_token() {
Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
if ws.next_sibling_or_token()?.into_token()? == r {
- editor.replace(ws, make.whitespace(&format!("\n{indent}")));
+ editor.replace(ws, editor.make().whitespace(&format!("\n{indent}")));
}
}
Some(ws) if ws.kind() == T!['}'] => {
- editor.insert(Position::after(l), make.whitespace(&format!("\n{indent}")));
+ editor.insert(Position::after(l), editor.make().whitespace(&format!("\n{indent}")));
}
_ => (),
}
@@ -332,8 +324,6 @@ impl Removable for ast::TypeBoundList {
impl Removable for ast::Use {
fn remove(&self, editor: &mut SyntaxEditor) {
- let make = SyntaxFactory::without_mappings();
-
let next_ws = self
.syntax()
.next_sibling_or_token()
@@ -345,7 +335,7 @@ impl Removable for ast::Use {
if rest.is_empty() {
editor.delete(next_ws.syntax());
} else {
- editor.replace(next_ws.syntax(), make.whitespace(rest));
+ editor.replace(next_ws.syntax(), editor.make().whitespace(rest));
}
}
}
@@ -379,7 +369,7 @@ mod tests {
use stdx::trim_indent;
use test_utils::assert_eq_text;
- use crate::SourceFile;
+ use crate::{SourceFile, ast::syntax_factory::SyntaxFactory};
use super::*;