aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax')
-rw-r--r--crates/syntax/Cargo.toml3
-rw-r--r--crates/syntax/src/algo.rs13
-rw-r--r--crates/syntax/src/ast/token_ext.rs27
3 files changed, 33 insertions, 10 deletions
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 1fe907753..c6a6f11e1 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "688.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "691.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
@@ -28,6 +28,7 @@ stdx = { path = "../stdx", version = "0.0.0" }
28text_edit = { path = "../text_edit", version = "0.0.0" } 28text_edit = { path = "../text_edit", version = "0.0.0" }
29parser = { path = "../parser", version = "0.0.0" } 29parser = { path = "../parser", version = "0.0.0" }
30test_utils = { path = "../test_utils", version = "0.0.0" } 30test_utils = { path = "../test_utils", version = "0.0.0" }
31profile = { path = "../profile", version = "0.0.0" }
31 32
32[dev-dependencies] 33[dev-dependencies]
33walkdir = "2.3.1" 34walkdir = "2.3.1"
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 320c430c9..ee89d9867 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -127,6 +127,8 @@ pub struct TreeDiff {
127 127
128impl TreeDiff { 128impl TreeDiff {
129 pub fn into_text_edit(&self, builder: &mut TextEditBuilder) { 129 pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
130 let _p = profile::span("into_text_edit");
131
130 for (anchor, to) in self.insertions.iter() { 132 for (anchor, to) in self.insertions.iter() {
131 let offset = match anchor { 133 let offset = match anchor {
132 TreeDiffInsertPos::After(it) => it.text_range().end(), 134 TreeDiffInsertPos::After(it) => it.text_range().end(),
@@ -154,6 +156,8 @@ impl TreeDiff {
154/// 156///
155/// This function tries to find a fine-grained diff. 157/// This function tries to find a fine-grained diff.
156pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { 158pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
159 let _p = profile::span("diff");
160
157 let mut diff = TreeDiff { 161 let mut diff = TreeDiff {
158 replacements: FxHashMap::default(), 162 replacements: FxHashMap::default(),
159 insertions: FxIndexMap::default(), 163 insertions: FxIndexMap::default(),
@@ -467,6 +471,8 @@ impl<'a> SyntaxRewriter<'a> {
467 } 471 }
468 472
469 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { 473 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode {
474 let _p = profile::span("rewrite");
475
470 if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() { 476 if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() {
471 return node.clone(); 477 return node.clone();
472 } 478 }
@@ -483,6 +489,7 @@ impl<'a> SyntaxRewriter<'a> {
483 /// 489 ///
484 /// Returns `None` when there are no replacements. 490 /// Returns `None` when there are no replacements.
485 pub fn rewrite_root(&self) -> Option<SyntaxNode> { 491 pub fn rewrite_root(&self) -> Option<SyntaxNode> {
492 let _p = profile::span("rewrite_root");
486 fn element_to_node_or_parent(element: &SyntaxElement) -> SyntaxNode { 493 fn element_to_node_or_parent(element: &SyntaxElement) -> SyntaxNode {
487 match element { 494 match element {
488 SyntaxElement::Node(it) => it.clone(), 495 SyntaxElement::Node(it) => it.clone(),
@@ -517,6 +524,8 @@ impl<'a> SyntaxRewriter<'a> {
517 } 524 }
518 525
519 fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode { 526 fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode {
527 let _p = profile::span("rewrite_children");
528
520 // FIXME: this could be made much faster. 529 // FIXME: this could be made much faster.
521 let mut new_children = Vec::new(); 530 let mut new_children = Vec::new();
522 if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) { 531 if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) {
@@ -533,6 +542,8 @@ impl<'a> SyntaxRewriter<'a> {
533 acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, 542 acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
534 element: &SyntaxElement, 543 element: &SyntaxElement,
535 ) { 544 ) {
545 let _p = profile::span("rewrite_self");
546
536 if let Some(replacement) = self.replacement(&element) { 547 if let Some(replacement) = self.replacement(&element) {
537 match replacement { 548 match replacement {
538 Replacement::Single(element) => acc.push(element_to_green(element)), 549 Replacement::Single(element) => acc.push(element_to_green(element)),
@@ -588,6 +599,8 @@ fn with_children(
588 parent: &SyntaxNode, 599 parent: &SyntaxNode,
589 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, 600 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
590) -> SyntaxNode { 601) -> SyntaxNode {
602 let _p = profile::span("with_children");
603
591 let len = new_children.iter().map(|it| it.text_len()).sum::<TextSize>(); 604 let len = new_children.iter().map(|it| it.text_len()).sum::<TextSize>();
592 let new_node = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children); 605 let new_node = rowan::GreenNode::new(rowan::SyntaxKind(parent.kind() as u16), new_children);
593 let new_root_node = parent.replace_with(new_node); 606 let new_root_node = parent.replace_with(new_node);
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 0c178039e..fa40e64e8 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -130,19 +130,28 @@ impl ast::String {
130 let text = self.text().as_str(); 130 let text = self.text().as_str();
131 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 131 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
132 132
133 let mut buf = String::with_capacity(text.len()); 133 let mut buf = String::new();
134 let mut text_iter = text.chars();
134 let mut has_error = false; 135 let mut has_error = false;
135 unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { 136 unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
136 Ok(c) => buf.push(c), 137 unescaped_char,
137 Err(_) => has_error = true, 138 buf.capacity() == 0,
139 ) {
140 (Ok(c), false) => buf.push(c),
141 (Ok(c), true) if Some(c) == text_iter.next() => (),
142 (Ok(c), true) => {
143 buf.reserve_exact(text.len());
144 buf.push_str(&text[..char_range.start]);
145 buf.push(c);
146 }
147 (Err(_), _) => has_error = true,
138 }); 148 });
139 149
140 if has_error { 150 match (has_error, buf.capacity() == 0) {
141 return None; 151 (true, _) => None,
152 (false, true) => Some(Cow::Borrowed(text)),
153 (false, false) => Some(Cow::Owned(buf)),
142 } 154 }
143 // FIXME: don't actually allocate for borrowed case
144 let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) };
145 Some(res)
146 } 155 }
147 156
148 pub fn quote_offsets(&self) -> Option<QuoteOffsets> { 157 pub fn quote_offsets(&self) -> Option<QuoteOffsets> {