//! FIXME: write short doc here
-use std::{fmt, hash::BuildHasherDefault, ops::RangeInclusive};
+use std::{hash::BuildHasherDefault, ops::RangeInclusive};
use indexmap::IndexMap;
use itertools::Itertools;
with_children(parent, new_children)
}
-#[derive(Debug, PartialEq, Eq, Hash)]
-enum InsertPos {
- FirstChildOf(SyntaxNode),
- After(SyntaxElement),
-}
-
-#[derive(Default)]
-pub(crate) struct SyntaxRewriter<'a> {
- //FIXME: add debug_assertions that all elements are in fact from the same file.
- replacements: FxHashMap<SyntaxElement, Replacement>,
- insertions: IndexMap<InsertPos, Vec<SyntaxElement>>,
- _pd: std::marker::PhantomData<&'a ()>,
-}
-
-impl fmt::Debug for SyntaxRewriter<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SyntaxRewriter")
- .field("replacements", &self.replacements)
- .field("insertions", &self.insertions)
- .finish()
- }
-}
-
-impl SyntaxRewriter<'_> {
- pub(crate) fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) {
- let what = what.clone().into();
- let replacement = Replacement::Single(with.clone().into());
- self.replacements.insert(what, replacement);
- }
-
- pub(crate) fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode {
- let _p = profile::span("rewrite");
-
- if self.replacements.is_empty() && self.insertions.is_empty() {
- return node.clone();
- }
- let green = self.rewrite_children(node);
- with_green(node, green)
- }
-
- pub(crate) fn rewrite_ast<N: AstNode>(self, node: &N) -> N {
- N::cast(self.rewrite(node.syntax())).unwrap()
- }
-
- fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> {
- self.replacements.get(element).cloned()
- }
-
- fn insertions(&self, pos: &InsertPos) -> Option<impl Iterator<Item = SyntaxElement> + '_> {
- self.insertions.get(pos).map(|insertions| insertions.iter().cloned())
- }
-
- fn rewrite_children(&self, node: &SyntaxNode) -> rowan::GreenNode {
- let _p = profile::span("rewrite_children");
-
- // FIXME: this could be made much faster.
- let mut new_children = Vec::new();
- if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) {
- new_children.extend(elements.map(element_to_green));
- }
- for child in node.children_with_tokens() {
- self.rewrite_self(&mut new_children, &child);
- }
-
- rowan::GreenNode::new(rowan::SyntaxKind(node.kind() as u16), new_children)
- }
-
- fn rewrite_self(
- &self,
- acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
- element: &SyntaxElement,
- ) {
- let _p = profile::span("rewrite_self");
-
- if let Some(replacement) = self.replacement(&element) {
- match replacement {
- Replacement::Single(element) => acc.push(element_to_green(element)),
- };
- } else {
- match element {
- NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().to_owned())),
- NodeOrToken::Node(it) => {
- acc.push(NodeOrToken::Node(self.rewrite_children(it)));
- }
- }
- }
- if let Some(elements) = self.insertions(&InsertPos::After(element.clone())) {
- acc.extend(elements.map(element_to_green));
- }
- }
-}
-
-fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> {
- match element {
- NodeOrToken::Node(it) => NodeOrToken::Node(it.green().into_owned()),
- NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()),
- }
-}
-
-#[derive(Clone, Debug)]
-enum Replacement {
- Single(SyntaxElement),
-}
-
fn with_children(
parent: &SyntaxNode,
new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
//! immutable, all function here return a fresh copy of the tree, instead of
//! doing an in-place modification.
use std::{
- array, fmt, iter,
+ fmt, iter,
ops::{self, RangeInclusive},
};
use arrayvec::ArrayVec;
use crate::{
- algo::{self, SyntaxRewriter},
+ algo,
ast::{
self,
make::{self, tokens},
- AstNode, GenericParamsOwner, NameOwner, TypeBoundsOwner,
+ AstNode, TypeBoundsOwner,
},
ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind,
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
to_insert.push(body.syntax().clone().into());
self.replace_children(single_node(old_body_or_semi), to_insert)
}
-
- #[must_use]
- pub fn with_generic_param_list(&self, generic_args: ast::GenericParamList) -> ast::Fn {
- if let Some(old) = self.generic_param_list() {
- return self.replace_descendant(old, generic_args);
- }
-
- let anchor = self.name().expect("The function must have a name").syntax().clone();
-
- let to_insert = [generic_args.syntax().clone().into()];
- self.insert_children(InsertPosition::After(anchor.into()), array::IntoIter::new(to_insert))
- }
}
fn make_multiline<N>(node: N) -> N
}
}
-impl ast::Use {
- #[must_use]
- pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::Use {
- if let Some(old) = self.use_tree() {
- return self.replace_descendant(old, use_tree);
- }
- self.clone()
- }
-}
-
impl ast::UseTree {
- #[must_use]
- pub fn with_path(&self, path: ast::Path) -> ast::UseTree {
- if let Some(old) = self.path() {
- return self.replace_descendant(old, path);
- }
- self.clone()
- }
-
- #[must_use]
- pub fn with_use_tree_list(&self, use_tree_list: ast::UseTreeList) -> ast::UseTree {
- if let Some(old) = self.use_tree_list() {
- return self.replace_descendant(old, use_tree_list);
- }
- self.clone()
- }
-
/// Splits off the given prefix, making it the path component of the use tree, appending the rest of the path to all UseTreeList items.
#[must_use]
pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree {
let new_syntax = algo::replace_children(self.syntax(), to_replace, to_insert);
Self::cast(new_syntax).unwrap()
}
-
- #[must_use]
- fn replace_descendant<D: AstNode>(&self, old: D, new: D) -> Self {
- let mut rewriter = SyntaxRewriter::default();
- rewriter.replace(old.syntax(), new.syntax());
- rewriter.rewrite_ast(self)
- }
fn indent_level(&self) -> IndentLevel {
IndentLevel::from_node(self.syntax())
}