Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/ast/edit_in_place.rs')
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs308
1 files changed, 0 insertions, 308 deletions
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
deleted file mode 100644
index d7f1844b13..0000000000
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ /dev/null
@@ -1,308 +0,0 @@
-//! Structural editing for ast.
-
-use std::iter::{empty, once, successors};
-
-use parser::T;
-
-use crate::{
- AstNode, AstToken, Direction,
- algo::{self, neighbor},
- ast::{self, make, syntax_factory::SyntaxFactory},
- syntax_editor::SyntaxEditor,
- ted,
-};
-
-use super::HasName;
-
-impl ast::GenericParamList {
- /// Constructs a matching [`ast::GenericArgList`]
- pub fn to_generic_args(&self, make: &SyntaxFactory) -> ast::GenericArgList {
- let args = self.generic_params().filter_map(|param| match param {
- ast::GenericParam::LifetimeParam(it) => {
- Some(ast::GenericArg::LifetimeArg(make.lifetime_arg(it.lifetime()?)))
- }
- ast::GenericParam::TypeParam(it) => {
- Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?))))
- }
- ast::GenericParam::ConstParam(it) => {
- // Name-only const params get parsed as `TypeArg`s
- Some(ast::GenericArg::TypeArg(make.type_arg(make.ty_name(it.name()?))))
- }
- });
-
- make::generic_arg_list(args)
- }
-}
-
-pub trait Removable: AstNode {
- fn remove(&self);
-}
-
-impl Removable for ast::UseTree {
- fn remove(&self) {
- for dir in [Direction::Next, Direction::Prev] {
- if let Some(next_use_tree) = neighbor(self, dir) {
- let separators = self
- .syntax()
- .siblings_with_tokens(dir)
- .skip(1)
- .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
- ted::remove_all_iter(separators);
- break;
- }
- }
- ted::remove(self.syntax());
- }
-}
-
-impl ast::UseTree {
- /// Editor variant of UseTree remove
- fn remove_with_editor(&self, editor: &SyntaxEditor) {
- for dir in [Direction::Next, Direction::Prev] {
- if let Some(next_use_tree) = neighbor(self, dir) {
- let separators = self
- .syntax()
- .siblings_with_tokens(dir)
- .skip(1)
- .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
- for separator in separators {
- editor.delete(separator);
- }
- break;
- }
- }
- editor.delete(self.syntax());
- }
-
- /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty.
- pub fn remove_recursive(self, editor: &SyntaxEditor) {
- let parent = self.syntax().parent();
-
- if let Some(u) = parent.clone().and_then(ast::Use::cast) {
- u.remove(editor);
- } else if let Some(u) = parent.and_then(ast::UseTreeList::cast) {
- if u.use_trees().nth(1).is_none()
- || u.use_trees().all(|use_tree| {
- use_tree.syntax() == self.syntax() || editor.deleted(use_tree.syntax())
- })
- {
- u.parent_use_tree().remove_recursive(editor);
- return;
- }
- self.remove_with_editor(editor);
- u.remove_unnecessary_braces(editor);
- }
- }
-
- pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
- match self.use_tree_list() {
- Some(it) => it,
- None => {
- let position = ted::Position::last_child_of(self.syntax());
- let use_tree_list = make::use_tree_list(empty()).clone_for_update();
- let mut elements = Vec::with_capacity(2);
- if self.coloncolon_token().is_none() {
- elements.push(make::token(T![::]).into());
- }
- elements.push(use_tree_list.syntax().clone().into());
- ted::insert_all_raw(position, elements);
- use_tree_list
- }
- }
- }
-
- /// Splits off the given prefix, making it the path component of the use tree,
- /// appending the rest of the path to all UseTreeList items.
- ///
- /// # Examples
- ///
- /// `prefix$0::suffix` -> `prefix::{suffix}`
- ///
- /// `prefix$0` -> `prefix::{self}`
- ///
- /// `prefix$0::*` -> `prefix::{*}`
- pub fn split_prefix(&self, prefix: &ast::Path) {
- debug_assert_eq!(self.path(), Some(prefix.top_path()));
- let path = self.path().unwrap();
- if &path == prefix && self.use_tree_list().is_none() {
- if self.star_token().is_some() {
- // path$0::* -> *
- if let Some(a) = self.coloncolon_token() {
- ted::remove(a)
- }
- ted::remove(prefix.syntax());
- } else {
- // path$0 -> self
- let self_suffix =
- make::path_unqualified(make::path_segment_self()).clone_for_update();
- ted::replace(path.syntax(), self_suffix.syntax());
- }
- } else if split_path_prefix(prefix).is_none() {
- return;
- }
- // At this point, prefix path is detached; _self_ use tree has suffix path.
- // Next, transform 'suffix' use tree into 'prefix::{suffix}'
- let subtree = self.clone_subtree().clone_for_update();
- ted::remove_all_iter(self.syntax().children_with_tokens());
- ted::insert(ted::Position::first_child_of(self.syntax()), prefix.syntax());
- self.get_or_create_use_tree_list().add_use_tree(subtree);
-
- fn split_path_prefix(prefix: &ast::Path) -> Option<()> {
- let parent = prefix.parent_path()?;
- let segment = parent.segment()?;
- if algo::has_errors(segment.syntax()) {
- return None;
- }
- for p in successors(parent.parent_path(), |it| it.parent_path()) {
- p.segment()?;
- }
- if let Some(a) = prefix.parent_path().and_then(|p| p.coloncolon_token()) {
- ted::remove(a)
- }
- ted::remove(prefix.syntax());
- Some(())
- }
- }
-
- /// Editor variant of `split_prefix`
- pub fn split_prefix_with_editor(&self, editor: &SyntaxEditor, prefix: &ast::Path) {
- debug_assert_eq!(self.path(), Some(prefix.top_path()));
-
- let make = editor.make();
- let path = self.path().unwrap();
- let suffix = if path == *prefix && self.use_tree_list().is_none() {
- if self.star_token().is_some() {
- make.use_tree_glob()
- } else {
- let self_path = make.path_unqualified(make.path_segment_self());
- make.use_tree(self_path, None, None, false)
- }
- } else {
- let suffix_segments = path.segments().skip(prefix.segments().count());
- let suffix_path = make.path_from_segments(suffix_segments, false);
- make.use_tree(
- suffix_path,
- self.use_tree_list(),
- self.rename(),
- self.star_token().is_some(),
- )
- };
- let use_tree_list = make.use_tree_list(once(suffix));
- let new_use_tree = make.use_tree(prefix.clone(), Some(use_tree_list), None, false);
-
- editor.replace(self.syntax(), new_use_tree.syntax());
- }
-
- /// Wraps the use tree in use tree list with no top level path (if it isn't already).
- ///
- /// # Examples
- ///
- /// `foo::bar` -> `{foo::bar}`
- ///
- /// `{foo::bar}` -> `{foo::bar}`
- pub fn wrap_in_tree_list(&self) -> Option<()> {
- if self.use_tree_list().is_some()
- && self.path().is_none()
- && self.star_token().is_none()
- && self.rename().is_none()
- {
- return None;
- }
- let subtree = self.clone_subtree().clone_for_update();
- ted::remove_all_iter(self.syntax().children_with_tokens());
- ted::append_child(
- self.syntax(),
- make::use_tree_list(once(subtree)).clone_for_update().syntax(),
- );
- Some(())
- }
-}
-
-impl ast::UseTreeList {
- pub fn add_use_tree(&self, use_tree: ast::UseTree) {
- let (position, elements) = match self.use_trees().last() {
- Some(last_tree) => (
- ted::Position::after(last_tree.syntax()),
- vec![
- make::token(T![,]).into(),
- make::tokens::single_space().into(),
- use_tree.syntax.into(),
- ],
- ),
- None => {
- let position = match self.l_curly_token() {
- Some(l_curly) => ted::Position::after(l_curly),
- None => ted::Position::last_child_of(self.syntax()),
- };
- (position, vec![use_tree.syntax.into()])
- }
- };
- ted::insert_all_raw(position, elements);
- }
-}
-
-impl ast::Use {
- fn remove(&self, editor: &SyntaxEditor) {
- let make = editor.make();
- let next_ws = self
- .syntax()
- .next_sibling_or_token()
- .and_then(|it| it.into_token())
- .and_then(ast::Whitespace::cast);
- if let Some(next_ws) = next_ws {
- let ws_text = next_ws.syntax().text();
- if let Some(rest) = ws_text.strip_prefix('\n') {
- let next_use_removed = next_ws
- .syntax()
- .next_sibling_or_token()
- .and_then(|it| it.into_node())
- .and_then(ast::Use::cast)
- .and_then(|use_| use_.use_tree())
- .is_some_and(|use_tree| editor.deleted(use_tree.syntax()));
- if rest.is_empty() || next_use_removed {
- editor.delete(next_ws.syntax());
- } else {
- editor.replace(next_ws.syntax(), make.whitespace(rest));
- }
- }
- }
- let prev_ws = self
- .syntax()
- .prev_sibling_or_token()
- .and_then(|it| it.into_token())
- .and_then(ast::Whitespace::cast);
- if let Some(prev_ws) = prev_ws {
- let ws_text = prev_ws.syntax().text();
- let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0);
- let rest = &ws_text[0..prev_newline];
- if rest.is_empty() {
- editor.delete(prev_ws.syntax());
- } else {
- editor.replace(prev_ws.syntax(), make.whitespace(rest));
- }
- }
-
- editor.delete(self.syntax());
- }
-}
-
-impl ast::RecordExprField {
- /// This will either replace the initializer, or in the case that this is a shorthand convert
- /// the initializer into the name ref and insert the expr as the new initializer.
- pub fn replace_expr(&self, editor: &SyntaxEditor, expr: ast::Expr) {
- if self.name_ref().is_some() {
- if let Some(prev) = self.expr() {
- editor.replace(prev.syntax(), expr.syntax());
- }
- } else if let Some(ast::Expr::PathExpr(path_expr)) = self.expr()
- && let Some(path) = path_expr.path()
- && let Some(name_ref) = path.as_single_name_ref()
- {
- // shorthand `{ x }` → expand to `{ x: expr }`
- let new_field = editor
- .make()
- .record_expr_field(editor.make().name_ref(&name_ref.text()), Some(expr));
- editor.replace(self.syntax(), new_field.syntax());
- }
- }
-}