aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-05-10 17:04:41 +0100
committerAleksey Kladov <[email protected]>2021-05-14 14:19:27 +0100
commit0650f77dd9defaf352f81c5ee4ee73a1eae942b7 (patch)
tree4758b6ea999292cf18a078dd942f51621a2d68ea /crates
parentab528e85f71da188722ae031b31a3a70bac1cadd (diff)
internal: remove one more immutable tree
Diffstat (limited to 'crates')
-rw-r--r--crates/ide_db/src/helpers/merge_imports.rs34
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/algo.rs35
-rw-r--r--crates/syntax/src/ast.rs6
-rw-r--r--crates/syntax/src/ast/make.rs10
5 files changed, 33 insertions, 54 deletions
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index af2a51a4d..475ef99b5 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -2,8 +2,9 @@
2use std::cmp::Ordering; 2use std::cmp::Ordering;
3 3
4use itertools::{EitherOrBoth, Itertools}; 4use itertools::{EitherOrBoth, Itertools};
5use syntax::ast::{ 5use syntax::{
6 self, edit::AstNodeEdit, make, AstNode, AttrsOwner, PathSegmentKind, VisibilityOwner, 6 ast::{self, make, AstNode, AttrsOwner, PathSegmentKind, VisibilityOwner},
7 ted,
7}; 8};
8 9
9/// What type of merges are allowed. 10/// What type of merges are allowed.
@@ -65,7 +66,7 @@ pub fn try_merge_trees(
65 } else { 66 } else {
66 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix)) 67 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
67 }; 68 };
68 recursive_merge(&lhs, &rhs, merge) 69 recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update())
69} 70}
70 71
71/// Recursively "zips" together lhs and rhs. 72/// Recursively "zips" together lhs and rhs.
@@ -78,7 +79,8 @@ fn recursive_merge(
78 .use_tree_list() 79 .use_tree_list()
79 .into_iter() 80 .into_iter()
80 .flat_map(|list| list.use_trees()) 81 .flat_map(|list| list.use_trees())
81 // we use Option here to early return from this function(this is not the same as a `filter` op) 82 // We use Option here to early return from this function(this is not the
83 // same as a `filter` op).
82 .map(|tree| match merge.is_tree_allowed(&tree) { 84 .map(|tree| match merge.is_tree_allowed(&tree) {
83 true => Some(tree), 85 true => Some(tree),
84 false => None, 86 false => None,
@@ -111,8 +113,10 @@ fn recursive_merge(
111 let tree_is_self = |tree: ast::UseTree| { 113 let tree_is_self = |tree: ast::UseTree| {
112 tree.path().as_ref().map(path_is_self).unwrap_or(false) 114 tree.path().as_ref().map(path_is_self).unwrap_or(false)
113 }; 115 };
114 // check if only one of the two trees has a tree list, and whether that then contains `self` or not. 116 // Check if only one of the two trees has a tree list, and
115 // If this is the case we can skip this iteration since the path without the list is already included in the other one via `self` 117 // whether that then contains `self` or not. If this is the
118 // case we can skip this iteration since the path without
119 // the list is already included in the other one via `self`.
116 let tree_contains_self = |tree: &ast::UseTree| { 120 let tree_contains_self = |tree: &ast::UseTree| {
117 tree.use_tree_list() 121 tree.use_tree_list()
118 .map(|tree_list| tree_list.use_trees().any(tree_is_self)) 122 .map(|tree_list| tree_list.use_trees().any(tree_is_self))
@@ -127,9 +131,11 @@ fn recursive_merge(
127 _ => (), 131 _ => (),
128 } 132 }
129 133
130 // glob imports arent part of the use-tree lists so we need to special handle them here as well 134 // Glob imports aren't part of the use-tree lists so we need
131 // this special handling is only required for when we merge a module import into a glob import of said module 135 // to special handle them here as well this special handling
132 // see the `merge_self_glob` or `merge_mod_into_glob` tests 136 // is only required for when we merge a module import into a
137 // glob import of said module see the `merge_self_glob` or
138 // `merge_mod_into_glob` tests.
133 if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() { 139 if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
134 *lhs_t = make::use_tree( 140 *lhs_t = make::use_tree(
135 make::path_unqualified(make::path_segment_self()), 141 make::path_unqualified(make::path_segment_self()),
@@ -165,11 +171,11 @@ fn recursive_merge(
165 } 171 }
166 } 172 }
167 173
168 Some(if let Some(old) = lhs.use_tree_list() { 174 let lhs = lhs.clone_subtree().clone_for_update();
169 lhs.replace_descendant(old, make::use_tree_list(use_trees)).clone_for_update() 175 if let Some(old) = lhs.use_tree_list() {
170 } else { 176 ted::replace(old.syntax(), make::use_tree_list(use_trees).syntax().clone_for_update());
171 lhs.clone() 177 }
172 }) 178 ast::UseTree::cast(lhs.syntax().clone_subtree())
173} 179}
174 180
175/// Traverses both paths until they differ, returning the common prefix of both. 181/// Traverses both paths until they differ, returning the common prefix of both.
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index c0bc59918..747f0b9eb 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "=0.13.0-pre.5" 16rowan = "=0.13.0-pre.6"
17rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.7" 19arrayvec = "0.7"
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 3f9b84ab9..825ea3185 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -337,7 +337,7 @@ enum InsertPos {
337} 337}
338 338
339#[derive(Default)] 339#[derive(Default)]
340pub struct SyntaxRewriter<'a> { 340pub(crate) struct SyntaxRewriter<'a> {
341 //FIXME: add debug_assertions that all elements are in fact from the same file. 341 //FIXME: add debug_assertions that all elements are in fact from the same file.
342 replacements: FxHashMap<SyntaxElement, Replacement>, 342 replacements: FxHashMap<SyntaxElement, Replacement>,
343 insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, 343 insertions: IndexMap<InsertPos, Vec<SyntaxElement>>,
@@ -354,13 +354,13 @@ impl fmt::Debug for SyntaxRewriter<'_> {
354} 354}
355 355
356impl SyntaxRewriter<'_> { 356impl SyntaxRewriter<'_> {
357 pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { 357 pub(crate) fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) {
358 let what = what.clone().into(); 358 let what = what.clone().into();
359 let replacement = Replacement::Single(with.clone().into()); 359 let replacement = Replacement::Single(with.clone().into());
360 self.replacements.insert(what, replacement); 360 self.replacements.insert(what, replacement);
361 } 361 }
362 362
363 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { 363 pub(crate) fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode {
364 let _p = profile::span("rewrite"); 364 let _p = profile::span("rewrite");
365 365
366 if self.replacements.is_empty() && self.insertions.is_empty() { 366 if self.replacements.is_empty() && self.insertions.is_empty() {
@@ -370,37 +370,10 @@ impl SyntaxRewriter<'_> {
370 with_green(node, green) 370 with_green(node, green)
371 } 371 }
372 372
373 pub fn rewrite_ast<N: AstNode>(self, node: &N) -> N { 373 pub(crate) fn rewrite_ast<N: AstNode>(self, node: &N) -> N {
374 N::cast(self.rewrite(node.syntax())).unwrap() 374 N::cast(self.rewrite(node.syntax())).unwrap()
375 } 375 }
376 376
377 /// Returns a node that encompasses all replacements to be done by this rewriter.
378 ///
379 /// Passing the returned node to `rewrite` will apply all replacements queued up in `self`.
380 ///
381 /// Returns `None` when there are no replacements.
382 pub fn rewrite_root(&self) -> Option<SyntaxNode> {
383 let _p = profile::span("rewrite_root");
384 fn element_to_node_or_parent(element: &SyntaxElement) -> Option<SyntaxNode> {
385 match element {
386 SyntaxElement::Node(it) => Some(it.clone()),
387 SyntaxElement::Token(it) => it.parent(),
388 }
389 }
390
391 self.replacements
392 .keys()
393 .filter_map(element_to_node_or_parent)
394 .chain(self.insertions.keys().filter_map(|pos| match pos {
395 InsertPos::FirstChildOf(it) => Some(it.clone()),
396 InsertPos::After(it) => element_to_node_or_parent(it),
397 }))
398 // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does
399 // not replace the node passed to it.
400 .map(|it| it.parent().unwrap_or(it))
401 .fold1(|a, b| least_common_ancestor(&a, &b).unwrap())
402 }
403
404 fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { 377 fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> {
405 self.replacements.get(element).cloned() 378 self.replacements.get(element).cloned()
406 } 379 }
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index 7f472d4db..a8071b51d 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -47,6 +47,12 @@ pub trait AstNode {
47 { 47 {
48 Self::cast(self.syntax().clone_for_update()).unwrap() 48 Self::cast(self.syntax().clone_for_update()).unwrap()
49 } 49 }
50 fn clone_subtree(&self) -> Self
51 where
52 Self: Sized,
53 {
54 Self::cast(self.syntax().clone_subtree()).unwrap()
55 }
50} 56}
51 57
52/// Like `AstNode`, but wraps tokens rather than interior nodes. 58/// Like `AstNode`, but wraps tokens rather than interior nodes.
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 1998ad1f6..de04c8620 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -12,7 +12,7 @@
12use itertools::Itertools; 12use itertools::Itertools;
13use stdx::{format_to, never}; 13use stdx::{format_to, never};
14 14
15use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; 15use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};
16 16
17/// While the parent module defines basic atomic "constructors", the `ext` 17/// While the parent module defines basic atomic "constructors", the `ext`
18/// module defines shortcuts for common things. 18/// module defines shortcuts for common things.
@@ -601,17 +601,11 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
601 panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text) 601 panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
602 } 602 }
603 }; 603 };
604 let node = node.syntax().clone(); 604 let node = node.clone_subtree();
605 let node = unroot(node);
606 let node = N::cast(node).unwrap();
607 assert_eq!(node.syntax().text_range().start(), 0.into()); 605 assert_eq!(node.syntax().text_range().start(), 0.into());
608 node 606 node
609} 607}
610 608
611fn unroot(n: SyntaxNode) -> SyntaxNode {
612 SyntaxNode::new_root(n.green().into())
613}
614
615pub fn token(kind: SyntaxKind) -> SyntaxToken { 609pub fn token(kind: SyntaxKind) -> SyntaxToken {
616 tokens::SOURCE_FILE 610 tokens::SOURCE_FILE
617 .tree() 611 .tree()