Unnamed repository; edit this file 'description' to name the repository.
migrate move bounds to SyntaxEditor API
| -rw-r--r-- | crates/ide-assists/src/handlers/move_bounds.rs | 85 | ||||
| -rw-r--r-- | crates/syntax/src/ast/syntax_factory/constructors.rs | 7 |
2 files changed, 71 insertions, 21 deletions
diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs index e9b77a7294..01a46c3334 100644 --- a/crates/ide-assists/src/handlers/move_bounds.rs +++ b/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,11 +1,8 @@ use either::Either; use syntax::{ - ast::{ - self, AstNode, HasName, HasTypeBounds, - edit_in_place::{GenericParamsOwnerEdit, Removable}, - syntax_factory::SyntaxFactory, - }, + ast::{self, AstNode, HasGenericParams, HasName, HasTypeBounds, syntax_factory::SyntaxFactory}, match_ast, + syntax_editor::{Position, Removable}, }; use crate::{AssistContext, AssistId, Assists}; @@ -47,23 +44,70 @@ pub(crate) fn move_bounds_to_where_clause( AssistId::refactor_rewrite("move_bounds_to_where_clause"), "Move to where clause", target, - |edit| { - let type_param_list = edit.make_mut(type_param_list); - let parent = edit.make_syntax_mut(parent); + |builder| { + let mut edit = builder.make_editor(&parent); let make = SyntaxFactory::without_mappings(); - let where_clause: ast::WhereClause = match_ast! { - match parent { - ast::Fn(it) => it.get_or_create_where_clause(), - ast::Trait(it) => it.get_or_create_where_clause(), - ast::Impl(it) => it.get_or_create_where_clause(), - ast::Enum(it) => it.get_or_create_where_clause(), - ast::Struct(it) => it.get_or_create_where_clause(), - ast::TypeAlias(it) => it.get_or_create_where_clause(), - _ => return, + let new_preds: Vec<ast::WherePred> = type_param_list + .generic_params() + .filter_map(|param| build_predicate(param, &make)) + .collect(); + + let existing_where: Option<ast::WhereClause> = match_ast! { + match (&parent) { + ast::Fn(it) => it.where_clause(), + ast::Trait(it) => it.where_clause(), + ast::Impl(it) => it.where_clause(), + ast::Enum(it) => it.where_clause(), + ast::Struct(it) => it.where_clause(), + ast::TypeAlias(it) => it.where_clause(), + _ => None, } }; + let all_preds = existing_where.iter().flat_map(|wc| wc.predicates()).chain(new_preds); + let new_where = make.where_clause(all_preds); + + if let Some(existing) = &existing_where { + edit.replace(existing.syntax(), new_where.syntax()); + } else { + let pos: Option<Position> = match_ast! { + match (&parent) { + ast::Fn(it) => it.ret_type() + .map(|t| Position::after(t.syntax())) + .or_else(|| it.param_list().map(|t| Position::after(t.syntax()))), + ast::Trait(it) => it.generic_param_list() + .map(|t| Position::after(t.syntax())) + .or_else(|| it.name().map(|t| Position::after(t.syntax()))), + ast::Impl(it) => it.self_ty() + .map(|t| Position::after(t.syntax())), + ast::Enum(it) => it.generic_param_list() + .map(|t| Position::after(t.syntax())) + .or_else(|| it.name().map(|t| Position::after(t.syntax()))), + ast::Struct(it) => it.field_list() + .and_then(|fl| match fl { + ast::FieldList::TupleFieldList(it) => { + Some(Position::after(it.syntax())) + } + ast::FieldList::RecordFieldList(_) => None, + }) + .or_else(|| it.generic_param_list() + .map(|t| Position::after(t.syntax()))) + .or_else(|| it.name().map(|t| Position::after(t.syntax()))), + ast::TypeAlias(it) => it.generic_param_list() + .map(|t| Position::after(t.syntax())) + .or_else(|| it.name().map(|t| Position::after(t.syntax()))), + _ => None, + } + }; + if let Some(pos) = pos { + edit.insert_all( + pos, + vec![make.whitespace(" ").into(), new_where.syntax().clone().into()], + ); + } + } + for generic_param in type_param_list.generic_params() { let param: &dyn HasTypeBounds = match &generic_param { ast::GenericParam::TypeParam(t) => t, @@ -71,12 +115,11 @@ pub(crate) fn move_bounds_to_where_clause( ast::GenericParam::ConstParam(_) => continue, }; if let Some(tbl) = param.type_bound_list() { - if let Some(predicate) = build_predicate(generic_param, &make) { - where_clause.add_predicate(predicate) - } - tbl.remove() + tbl.remove(&mut edit); } } + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs index f50cd90ce9..40412c7733 100644 --- a/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -134,6 +134,13 @@ impl SyntaxFactory { make::where_pred(path, bounds).clone_for_update() } + pub fn where_clause( + &self, + predicates: impl IntoIterator<Item = ast::WherePred>, + ) -> ast::WhereClause { + make::where_clause(predicates).clone_for_update() + } + pub fn expr_field(&self, receiver: ast::Expr, field: &str) -> ast::FieldExpr { let ast::Expr::FieldExpr(ast) = make::expr_field(receiver.clone(), field).clone_for_update() |