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.rs399
1 files changed, 6 insertions, 393 deletions
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 7f59ae4213..46ea4daba8 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -9,221 +9,12 @@ use crate::{
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
SyntaxNode, SyntaxToken,
algo::{self, neighbor},
- ast::{self, HasGenericParams, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
- syntax_editor::{Position, SyntaxEditor},
+ ast::{self, edit::IndentLevel, make},
ted,
};
use super::{GenericParam, HasName};
-pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
- fn get_or_create_where_clause(&self) -> ast::WhereClause;
-}
-
-impl GenericParamsOwnerEdit for ast::Fn {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = if let Some(name) = self.name() {
- ted::Position::after(name.syntax)
- } else if let Some(fn_token) = self.fn_token() {
- ted::Position::after(fn_token)
- } else if let Some(param_list) = self.param_list() {
- ted::Position::before(param_list.syntax)
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let position = if let Some(ty) = self.ret_type() {
- ted::Position::after(ty.syntax())
- } else if let Some(param_list) = self.param_list() {
- ted::Position::after(param_list.syntax())
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-impl GenericParamsOwnerEdit for ast::Impl {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = match self.impl_token() {
- Some(imp_token) => ted::Position::after(imp_token),
- None => ted::Position::last_child_of(self.syntax()),
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let position = match self.assoc_item_list() {
- Some(items) => ted::Position::before(items.syntax()),
- None => ted::Position::last_child_of(self.syntax()),
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-impl GenericParamsOwnerEdit for ast::Trait {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = if let Some(name) = self.name() {
- ted::Position::after(name.syntax)
- } else if let Some(trait_token) = self.trait_token() {
- ted::Position::after(trait_token)
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let position = match (self.assoc_item_list(), self.semicolon_token()) {
- (Some(items), _) => ted::Position::before(items.syntax()),
- (_, Some(tok)) => ted::Position::before(tok),
- (None, None) => ted::Position::last_child_of(self.syntax()),
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-impl GenericParamsOwnerEdit for ast::TypeAlias {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = if let Some(name) = self.name() {
- ted::Position::after(name.syntax)
- } else if let Some(trait_token) = self.type_token() {
- ted::Position::after(trait_token)
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let position = match self.eq_token() {
- Some(tok) => ted::Position::before(tok),
- None => match self.semicolon_token() {
- Some(tok) => ted::Position::before(tok),
- None => ted::Position::last_child_of(self.syntax()),
- },
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-impl GenericParamsOwnerEdit for ast::Struct {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = if let Some(name) = self.name() {
- ted::Position::after(name.syntax)
- } else if let Some(struct_token) = self.struct_token() {
- ted::Position::after(struct_token)
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let tfl = self.field_list().and_then(|fl| match fl {
- ast::FieldList::RecordFieldList(_) => None,
- ast::FieldList::TupleFieldList(it) => Some(it),
- });
- let position = if let Some(tfl) = tfl {
- ted::Position::after(tfl.syntax())
- } else if let Some(gpl) = self.generic_param_list() {
- ted::Position::after(gpl.syntax())
- } else if let Some(name) = self.name() {
- ted::Position::after(name.syntax())
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-impl GenericParamsOwnerEdit for ast::Enum {
- fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
- match self.generic_param_list() {
- Some(it) => it,
- None => {
- let position = if let Some(name) = self.name() {
- ted::Position::after(name.syntax)
- } else if let Some(enum_token) = self.enum_token() {
- ted::Position::after(enum_token)
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_generic_param_list(position)
- }
- }
- }
-
- fn get_or_create_where_clause(&self) -> ast::WhereClause {
- if self.where_clause().is_none() {
- let position = if let Some(gpl) = self.generic_param_list() {
- ted::Position::after(gpl.syntax())
- } else if let Some(name) = self.name() {
- ted::Position::after(name.syntax())
- } else {
- ted::Position::last_child_of(self.syntax())
- };
- create_where_clause(position);
- }
- self.where_clause().unwrap()
- }
-}
-
-fn create_where_clause(position: ted::Position) {
- let where_clause = make::where_clause(empty()).clone_for_update();
- ted::insert(position, where_clause.syntax());
-}
-
-fn create_generic_param_list(position: ted::Position) -> ast::GenericParamList {
- let gpl = make::generic_param_list(empty()).clone_for_update();
- ted::insert_raw(position, gpl.syntax());
- gpl
-}
-
pub trait AttrsOwnerEdit: ast::HasAttrs {
fn remove_attrs_and_docs(&self) {
remove_attrs_and_docs(self.syntax());
@@ -723,10 +514,11 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
let indent = IndentLevel::from_node(node);
match l.next_sibling_or_token() {
- Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
- if ws.next_sibling_or_token()?.into_token()? == r {
- ted::replace(ws, make::tokens::whitespace(&format!("\n{indent}")));
- }
+ Some(ws)
+ if ws.kind() == SyntaxKind::WHITESPACE
+ && ws.next_sibling_or_token()?.into_token()? == r =>
+ {
+ ted::replace(ws, make::tokens::whitespace(&format!("\n{indent}")));
}
Some(ws) if ws.kind() == T!['}'] => {
ted::insert(ted::Position::after(l), make::tokens::whitespace(&format!("\n{indent}")));
@@ -736,128 +528,6 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
Some(())
}
-impl ast::IdentPat {
- pub fn set_pat(&self, pat: Option<ast::Pat>) {
- match pat {
- None => {
- if let Some(at_token) = self.at_token() {
- // Remove `@ Pat`
- let start = at_token.clone().into();
- let end = self
- .pat()
- .map(|it| it.syntax().clone().into())
- .unwrap_or_else(|| at_token.into());
-
- ted::remove_all(start..=end);
-
- // Remove any trailing ws
- if let Some(last) =
- self.syntax().last_token().filter(|it| it.kind() == WHITESPACE)
- {
- last.detach();
- }
- }
- }
- Some(pat) => {
- if let Some(old_pat) = self.pat() {
- // Replace existing pattern
- ted::replace(old_pat.syntax(), pat.syntax())
- } else if let Some(at_token) = self.at_token() {
- // Have an `@` token but not a pattern yet
- ted::insert(ted::Position::after(at_token), pat.syntax());
- } else {
- // Don't have an `@`, should have a name
- let name = self.name().unwrap();
-
- ted::insert_all(
- ted::Position::after(name.syntax()),
- vec![
- make::token(T![@]).into(),
- make::tokens::single_space().into(),
- pat.syntax().clone().into(),
- ],
- )
- }
- }
- }
- }
-
- pub fn set_pat_with_editor(
- &self,
- pat: Option<ast::Pat>,
- syntax_editor: &mut SyntaxEditor,
- syntax_factory: &SyntaxFactory,
- ) {
- match pat {
- None => {
- if let Some(at_token) = self.at_token() {
- // Remove `@ Pat`
- let start = at_token.clone().into();
- let end = self
- .pat()
- .map(|it| it.syntax().clone().into())
- .unwrap_or_else(|| at_token.into());
- syntax_editor.delete_all(start..=end);
-
- // Remove any trailing ws
- if let Some(last) =
- self.syntax().last_token().filter(|it| it.kind() == WHITESPACE)
- {
- last.detach();
- }
- }
- }
- Some(pat) => {
- if let Some(old_pat) = self.pat() {
- // Replace existing pattern
- syntax_editor.replace(old_pat.syntax(), pat.syntax())
- } else if let Some(at_token) = self.at_token() {
- // Have an `@` token but not a pattern yet
- syntax_editor.insert(Position::after(at_token), pat.syntax());
- } else {
- // Don't have an `@`, should have a name
- let name = self.name().unwrap();
-
- syntax_editor.insert_all(
- Position::after(name.syntax()),
- vec![
- syntax_factory.whitespace(" ").into(),
- syntax_factory.token(T![@]).into(),
- syntax_factory.whitespace(" ").into(),
- pat.syntax().clone().into(),
- ],
- )
- }
- }
- }
- }
-}
-
-pub trait HasVisibilityEdit: ast::HasVisibility {
- fn set_visibility(&self, visibility: Option<ast::Visibility>) {
- if let Some(visibility) = visibility {
- match self.visibility() {
- Some(current_visibility) => {
- ted::replace(current_visibility.syntax(), visibility.syntax())
- }
- None => {
- let vis_before = self
- .syntax()
- .children_with_tokens()
- .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
- .unwrap_or_else(|| self.syntax().first_child_or_token().unwrap());
-
- ted::insert(ted::Position::before(vis_before), visibility.syntax());
- }
- }
- } else if let Some(visibility) = self.visibility() {
- ted::remove(visibility.syntax());
- }
- }
-}
-
-impl<T: ast::HasVisibility> HasVisibilityEdit for T {}
-
pub trait Indent: AstNode + Clone + Sized {
fn indent_level(&self) -> IndentLevel {
IndentLevel::from_node(self.syntax())
@@ -879,8 +549,6 @@ impl<N: AstNode + Clone> Indent for N {}
#[cfg(test)]
mod tests {
- use std::fmt;
-
use parser::Edition;
use crate::SourceFile;
@@ -893,33 +561,6 @@ mod tests {
}
#[test]
- fn test_create_generic_param_list() {
- fn check_create_gpl<N: GenericParamsOwnerEdit + fmt::Display>(before: &str, after: &str) {
- let gpl_owner = ast_mut_from_text::<N>(before);
- gpl_owner.get_or_create_generic_param_list();
- assert_eq!(gpl_owner.to_string(), after);
- }
-
- check_create_gpl::<ast::Fn>("fn foo", "fn foo<>");
- check_create_gpl::<ast::Fn>("fn foo() {}", "fn foo<>() {}");
-
- check_create_gpl::<ast::Impl>("impl", "impl<>");
- check_create_gpl::<ast::Impl>("impl Struct {}", "impl<> Struct {}");
- check_create_gpl::<ast::Impl>("impl Trait for Struct {}", "impl<> Trait for Struct {}");
-
- check_create_gpl::<ast::Trait>("trait Trait<>", "trait Trait<>");
- check_create_gpl::<ast::Trait>("trait Trait<> {}", "trait Trait<> {}");
-
- check_create_gpl::<ast::Struct>("struct A", "struct A<>");
- check_create_gpl::<ast::Struct>("struct A;", "struct A<>;");
- check_create_gpl::<ast::Struct>("struct A();", "struct A<>();");
- check_create_gpl::<ast::Struct>("struct A {}", "struct A<> {}");
-
- check_create_gpl::<ast::Enum>("enum E", "enum E<>");
- check_create_gpl::<ast::Enum>("enum E {", "enum E<> {");
- }
-
- #[test]
fn test_increase_indent() {
let arm_list = ast_mut_from_text::<ast::Fn>(
"fn foo() {
@@ -936,32 +577,4 @@ mod tests {
}",
);
}
-
- #[test]
- fn test_ident_pat_set_pat() {
- #[track_caller]
- fn check(before: &str, expected: &str, pat: Option<ast::Pat>) {
- let pat = pat.map(|it| it.clone_for_update());
-
- let ident_pat = ast_mut_from_text::<ast::IdentPat>(&format!("fn f() {{ {before} }}"));
- ident_pat.set_pat(pat);
-
- let after = ast_mut_from_text::<ast::IdentPat>(&format!("fn f() {{ {expected} }}"));
- assert_eq!(ident_pat.to_string(), after.to_string());
- }
-
- // replacing
- check("let a @ _;", "let a @ ();", Some(make::tuple_pat([]).into()));
-
- // note: no trailing semicolon is added for the below tests since it
- // seems to be picked up by the ident pat during error recovery?
-
- // adding
- check("let a ", "let a @ ()", Some(make::tuple_pat([]).into()));
- check("let a @ ", "let a @ ()", Some(make::tuple_pat([]).into()));
-
- // removing
- check("let a @ ()", "let a", None);
- check("let a @ ", "let a", None);
- }
}