diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide_db/src/helpers/merge_imports.rs | 4 | ||||
-rw-r--r-- | crates/syntax/src/algo.rs | 106 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 51 |
3 files changed, 7 insertions, 154 deletions
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs index 475ef99b5..8fb40e837 100644 --- a/crates/ide_db/src/helpers/merge_imports.rs +++ b/crates/ide_db/src/helpers/merge_imports.rs | |||
@@ -42,10 +42,12 @@ pub fn try_merge_imports( | |||
42 | return None; | 42 | return None; |
43 | } | 43 | } |
44 | 44 | ||
45 | let lhs = lhs.clone_subtree().clone_for_update(); | ||
45 | let lhs_tree = lhs.use_tree()?; | 46 | let lhs_tree = lhs.use_tree()?; |
46 | let rhs_tree = rhs.use_tree()?; | 47 | let rhs_tree = rhs.use_tree()?; |
47 | let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?; | 48 | let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?; |
48 | Some(lhs.with_use_tree(merged).clone_for_update()) | 49 | ted::replace(lhs_tree.syntax(), merged.syntax()); |
50 | Some(lhs) | ||
49 | } | 51 | } |
50 | 52 | ||
51 | pub fn try_merge_trees( | 53 | pub fn try_merge_trees( |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 825ea3185..241713c48 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{fmt, hash::BuildHasherDefault, ops::RangeInclusive}; | 3 | use std::{hash::BuildHasherDefault, ops::RangeInclusive}; |
4 | 4 | ||
5 | use indexmap::IndexMap; | 5 | use indexmap::IndexMap; |
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
@@ -330,110 +330,6 @@ fn _replace_children( | |||
330 | with_children(parent, new_children) | 330 | with_children(parent, new_children) |
331 | } | 331 | } |
332 | 332 | ||
333 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
334 | enum InsertPos { | ||
335 | FirstChildOf(SyntaxNode), | ||
336 | After(SyntaxElement), | ||
337 | } | ||
338 | |||
339 | #[derive(Default)] | ||
340 | pub(crate) struct SyntaxRewriter<'a> { | ||
341 | //FIXME: add debug_assertions that all elements are in fact from the same file. | ||
342 | replacements: FxHashMap<SyntaxElement, Replacement>, | ||
343 | insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, | ||
344 | _pd: std::marker::PhantomData<&'a ()>, | ||
345 | } | ||
346 | |||
347 | impl fmt::Debug for SyntaxRewriter<'_> { | ||
348 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
349 | f.debug_struct("SyntaxRewriter") | ||
350 | .field("replacements", &self.replacements) | ||
351 | .field("insertions", &self.insertions) | ||
352 | .finish() | ||
353 | } | ||
354 | } | ||
355 | |||
356 | impl SyntaxRewriter<'_> { | ||
357 | pub(crate) fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { | ||
358 | let what = what.clone().into(); | ||
359 | let replacement = Replacement::Single(with.clone().into()); | ||
360 | self.replacements.insert(what, replacement); | ||
361 | } | ||
362 | |||
363 | pub(crate) fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { | ||
364 | let _p = profile::span("rewrite"); | ||
365 | |||
366 | if self.replacements.is_empty() && self.insertions.is_empty() { | ||
367 | return node.clone(); | ||
368 | } | ||
369 | let green = self.rewrite_children(node); | ||
370 | with_green(node, green) | ||
371 | } | ||
372 | |||
373 | pub(crate) fn rewrite_ast<N: AstNode>(self, node: &N) -> N { | ||
374 | N::cast(self.rewrite(node.syntax())).unwrap() | ||
375 | } | ||
376 | |||
377 | fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { | ||
378 | self.replacements.get(element).cloned() | ||
379 | } | ||
380 | |||
381 | fn insertions(&self, pos: &InsertPos) -> Option<impl Iterator<Item = SyntaxElement> + '_> { | ||
382 | self.insertions.get(pos).map(|insertions| insertions.iter().cloned()) | ||
383 | } | ||
384 | |||
385 | fn rewrite_children(&self, node: &SyntaxNode) -> rowan::GreenNode { | ||
386 | let _p = profile::span("rewrite_children"); | ||
387 | |||
388 | // FIXME: this could be made much faster. | ||
389 | let mut new_children = Vec::new(); | ||
390 | if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) { | ||
391 | new_children.extend(elements.map(element_to_green)); | ||
392 | } | ||
393 | for child in node.children_with_tokens() { | ||
394 | self.rewrite_self(&mut new_children, &child); | ||
395 | } | ||
396 | |||
397 | rowan::GreenNode::new(rowan::SyntaxKind(node.kind() as u16), new_children) | ||
398 | } | ||
399 | |||
400 | fn rewrite_self( | ||
401 | &self, | ||
402 | acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, | ||
403 | element: &SyntaxElement, | ||
404 | ) { | ||
405 | let _p = profile::span("rewrite_self"); | ||
406 | |||
407 | if let Some(replacement) = self.replacement(&element) { | ||
408 | match replacement { | ||
409 | Replacement::Single(element) => acc.push(element_to_green(element)), | ||
410 | }; | ||
411 | } else { | ||
412 | match element { | ||
413 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().to_owned())), | ||
414 | NodeOrToken::Node(it) => { | ||
415 | acc.push(NodeOrToken::Node(self.rewrite_children(it))); | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | if let Some(elements) = self.insertions(&InsertPos::After(element.clone())) { | ||
420 | acc.extend(elements.map(element_to_green)); | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | |||
425 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | ||
426 | match element { | ||
427 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().into_owned()), | ||
428 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), | ||
429 | } | ||
430 | } | ||
431 | |||
432 | #[derive(Clone, Debug)] | ||
433 | enum Replacement { | ||
434 | Single(SyntaxElement), | ||
435 | } | ||
436 | |||
437 | fn with_children( | 333 | fn with_children( |
438 | parent: &SyntaxNode, | 334 | parent: &SyntaxNode, |
439 | new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, | 335 | new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 78c0dc102..10ec94cd2 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -2,18 +2,18 @@ | |||
2 | //! immutable, all function here return a fresh copy of the tree, instead of | 2 | //! immutable, all function here return a fresh copy of the tree, instead of |
3 | //! doing an in-place modification. | 3 | //! doing an in-place modification. |
4 | use std::{ | 4 | use std::{ |
5 | array, fmt, iter, | 5 | fmt, iter, |
6 | ops::{self, RangeInclusive}, | 6 | ops::{self, RangeInclusive}, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use arrayvec::ArrayVec; | 9 | use arrayvec::ArrayVec; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | algo::{self, SyntaxRewriter}, | 12 | algo, |
13 | ast::{ | 13 | ast::{ |
14 | self, | 14 | self, |
15 | make::{self, tokens}, | 15 | make::{self, tokens}, |
16 | AstNode, GenericParamsOwner, NameOwner, TypeBoundsOwner, | 16 | AstNode, TypeBoundsOwner, |
17 | }, | 17 | }, |
18 | ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind, | 18 | ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind, |
19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
@@ -46,18 +46,6 @@ impl ast::Fn { | |||
46 | to_insert.push(body.syntax().clone().into()); | 46 | to_insert.push(body.syntax().clone().into()); |
47 | self.replace_children(single_node(old_body_or_semi), to_insert) | 47 | self.replace_children(single_node(old_body_or_semi), to_insert) |
48 | } | 48 | } |
49 | |||
50 | #[must_use] | ||
51 | pub fn with_generic_param_list(&self, generic_args: ast::GenericParamList) -> ast::Fn { | ||
52 | if let Some(old) = self.generic_param_list() { | ||
53 | return self.replace_descendant(old, generic_args); | ||
54 | } | ||
55 | |||
56 | let anchor = self.name().expect("The function must have a name").syntax().clone(); | ||
57 | |||
58 | let to_insert = [generic_args.syntax().clone().into()]; | ||
59 | self.insert_children(InsertPosition::After(anchor.into()), array::IntoIter::new(to_insert)) | ||
60 | } | ||
61 | } | 49 | } |
62 | 50 | ||
63 | fn make_multiline<N>(node: N) -> N | 51 | fn make_multiline<N>(node: N) -> N |
@@ -313,33 +301,7 @@ impl ast::PathSegment { | |||
313 | } | 301 | } |
314 | } | 302 | } |
315 | 303 | ||
316 | impl ast::Use { | ||
317 | #[must_use] | ||
318 | pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::Use { | ||
319 | if let Some(old) = self.use_tree() { | ||
320 | return self.replace_descendant(old, use_tree); | ||
321 | } | ||
322 | self.clone() | ||
323 | } | ||
324 | } | ||
325 | |||
326 | impl ast::UseTree { | 304 | impl ast::UseTree { |
327 | #[must_use] | ||
328 | pub fn with_path(&self, path: ast::Path) -> ast::UseTree { | ||
329 | if let Some(old) = self.path() { | ||
330 | return self.replace_descendant(old, path); | ||
331 | } | ||
332 | self.clone() | ||
333 | } | ||
334 | |||
335 | #[must_use] | ||
336 | pub fn with_use_tree_list(&self, use_tree_list: ast::UseTreeList) -> ast::UseTree { | ||
337 | if let Some(old) = self.use_tree_list() { | ||
338 | return self.replace_descendant(old, use_tree_list); | ||
339 | } | ||
340 | self.clone() | ||
341 | } | ||
342 | |||
343 | /// Splits off the given prefix, making it the path component of the use tree, appending the rest of the path to all UseTreeList items. | 305 | /// Splits off the given prefix, making it the path component of the use tree, appending the rest of the path to all UseTreeList items. |
344 | #[must_use] | 306 | #[must_use] |
345 | pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree { | 307 | pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree { |
@@ -664,13 +626,6 @@ pub trait AstNodeEdit: AstNode + Clone + Sized { | |||
664 | let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert); | 626 | let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert); |
665 | Self::cast(new_syntax).unwrap() | 627 | Self::cast(new_syntax).unwrap() |
666 | } | 628 | } |
667 | |||
668 | #[must_use] | ||
669 | fn replace_descendant<D: AstNode>(&self, old: D, new: D) -> Self { | ||
670 | let mut rewriter = SyntaxRewriter::default(); | ||
671 | rewriter.replace(old.syntax(), new.syntax()); | ||
672 | rewriter.rewrite_ast(self) | ||
673 | } | ||
674 | fn indent_level(&self) -> IndentLevel { | 629 | fn indent_level(&self) -> IndentLevel { |
675 | IndentLevel::from_node(self.syntax()) | 630 | IndentLevel::from_node(self.syntax()) |
676 | } | 631 | } |