Skip to content

Commit 3d5be5b

Browse files
committed
Fix accidently quadratic syntax rewriter
Switching from SyntaxNode to GreenNode is a costly operation (b/c dereferencing a synax ptr in `with_green` is linear), so we should avoid that.
1 parent 78de7f0 commit 3d5be5b

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

crates/syntax/src/algo.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ impl<'a> SyntaxRewriter<'a> {
476476
if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() {
477477
return node.clone();
478478
}
479-
self.rewrite_children(node)
479+
let green = self.rewrite_children(node);
480+
with_green(node, green)
480481
}
481482

482483
pub fn rewrite_ast<N: AstNode>(self, node: &N) -> N {
@@ -523,7 +524,7 @@ impl<'a> SyntaxRewriter<'a> {
523524
self.insertions.get(pos).map(|insertions| insertions.iter().cloned())
524525
}
525526

526-
fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode {
527+
fn rewrite_children(&self, node: &SyntaxNode) -> rowan::GreenNode {
527528
let _p = profile::span("rewrite_children");
528529

529530
// FIXME: this could be made much faster.
@@ -534,7 +535,8 @@ impl<'a> SyntaxRewriter<'a> {
534535
for child in node.children_with_tokens() {
535536
self.rewrite_self(&mut new_children, &child);
536537
}
537-
with_children(node, new_children)
538+
539+
rowan::GreenNode::new(rowan::SyntaxKind(node.kind() as u16), new_children)
538540
}
539541

540542
fn rewrite_self(
@@ -556,7 +558,7 @@ impl<'a> SyntaxRewriter<'a> {
556558
match element {
557559
NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().clone())),
558560
NodeOrToken::Node(it) => {
559-
acc.push(NodeOrToken::Node(self.rewrite_children(it).green().clone()));
561+
acc.push(NodeOrToken::Node(self.rewrite_children(it)));
560562
}
561563
}
562564
}
@@ -601,14 +603,18 @@ fn with_children(
601603
) -> SyntaxNode {
602604
let _p = profile::span("with_children");
603605

604-
let len = new_children.iter().map(|it| it.text_len()).sum::<TextSize>();
605-
let new_node = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children);
606-
let new_root_node = parent.replace_with(new_node);
606+
let new_green = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children);
607+
with_green(parent, new_green)
608+
}
609+
610+
fn with_green(syntax_node: &SyntaxNode, green: rowan::GreenNode) -> SyntaxNode {
611+
let len = green.children().map(|it| it.text_len()).sum::<TextSize>();
612+
let new_root_node = syntax_node.replace_with(green);
607613
let new_root_node = SyntaxNode::new_root(new_root_node);
608614

609615
// FIXME: use a more elegant way to re-fetch the node (#1185), make
610616
// `range` private afterwards
611-
let mut ptr = SyntaxNodePtr::new(parent);
617+
let mut ptr = SyntaxNodePtr::new(syntax_node);
612618
ptr.range = TextRange::at(ptr.range.start(), len);
613619
ptr.to_node(&new_root_node)
614620
}

0 commit comments

Comments
 (0)