Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21734 from Shourya742/2026-03-02-migrate-already-migrated-assist-to-syntaxFactory
Replace make to syntax factory from already migrated syntax factory assist
A4-Tacks 7 weeks ago
parent fad5c3d · parent 0e510d9 · commit 6522eb8
-rw-r--r--crates/ide-assists/src/handlers/add_turbo_fish.rs13
-rw-r--r--crates/ide-assists/src/handlers/convert_bool_to_enum.rs89
-rw-r--r--crates/ide-assists/src/handlers/extract_type_alias.rs27
-rw-r--r--crates/ide-assists/src/handlers/generate_default_from_new.rs13
-rw-r--r--crates/ide-assists/src/handlers/generate_fn_type_alias.rs20
-rw-r--r--crates/ide-assists/src/handlers/move_bounds.rs53
-rw-r--r--crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs15
-rw-r--r--crates/syntax/src/ast/syntax_factory/constructors.rs70
-rw-r--r--crates/syntax/src/syntax_editor.rs2
-rw-r--r--crates/syntax/src/syntax_editor/edits.rs101
10 files changed, 296 insertions, 107 deletions
diff --git a/crates/ide-assists/src/handlers/add_turbo_fish.rs b/crates/ide-assists/src/handlers/add_turbo_fish.rs
index be13b04873..c5e722d87e 100644
--- a/crates/ide-assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -2,7 +2,7 @@ use either::Either;
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
AstNode,
- ast::{self, HasArgList, HasGenericArgs, make, syntax_factory::SyntaxFactory},
+ ast::{self, HasArgList, HasGenericArgs, syntax_factory::SyntaxFactory},
syntax_editor::Position,
};
@@ -94,20 +94,21 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
ident.text_range(),
|builder| {
let mut editor = builder.make_editor(let_stmt.syntax());
+ let make = SyntaxFactory::without_mappings();
if let_stmt.semicolon_token().is_none() {
editor.insert(
Position::last_child_of(let_stmt.syntax()),
- make::tokens::semicolon(),
+ make.token(syntax::SyntaxKind::SEMICOLON),
);
}
- let placeholder_ty = make::ty_placeholder().clone_for_update();
+ let placeholder_ty = make.ty_placeholder();
if let Some(pat) = let_stmt.pat() {
let elements = vec![
- make::token(syntax::SyntaxKind::COLON).into(),
- make::token(syntax::SyntaxKind::WHITESPACE).into(),
+ make.token(syntax::SyntaxKind::COLON).into(),
+ make.whitespace(" ").into(),
placeholder_ty.syntax().clone().into(),
];
editor.insert_all(Position::after(pat.syntax()), elements);
@@ -188,7 +189,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
/// This will create a turbofish generic arg list corresponding to the number of arguments
fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList {
- let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
+ let args = (0..number_of_arguments).map(|_| make.type_arg(make.ty_placeholder()).into());
make.generic_arg_list(args, true)
}
diff --git a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
index 434fbbae05..9347798100 100644
--- a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
+++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs
@@ -12,9 +12,10 @@ use ide_db::{
};
use itertools::Itertools;
use syntax::ast::edit::AstNodeEdit;
+use syntax::ast::syntax_factory::SyntaxFactory;
use syntax::{
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
- ast::{self, HasName, edit::IndentLevel, make},
+ ast::{self, HasName, edit::IndentLevel},
};
use crate::{
@@ -62,19 +63,28 @@ pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -
"Convert boolean to enum",
target,
|edit| {
+ let make = SyntaxFactory::without_mappings();
if let Some(ty) = &ty_annotation {
cov_mark::hit!(replaces_ty_annotation);
edit.replace(ty.syntax().text_range(), "Bool");
}
if let Some(initializer) = initializer {
- replace_bool_expr(edit, initializer);
+ replace_bool_expr(edit, initializer, &make);
}
let usages = definition.usages(&ctx.sema).all();
- add_enum_def(edit, ctx, &usages, target_node, &target_module);
+ add_enum_def(edit, ctx, &usages, target_node, &target_module, &make);
let mut delayed_mutations = Vec::new();
- replace_usages(edit, ctx, usages, definition, &target_module, &mut delayed_mutations);
+ replace_usages(
+ edit,
+ ctx,
+ usages,
+ definition,
+ &target_module,
+ &mut delayed_mutations,
+ &make,
+ );
for (scope, path) in delayed_mutations {
insert_use(&scope, path, &ctx.config.insert_use);
}
@@ -168,16 +178,16 @@ fn find_bool_node(ctx: &AssistContext<'_>) -> Option<BoolNodeData> {
}
}
-fn replace_bool_expr(edit: &mut SourceChangeBuilder, expr: ast::Expr) {
+fn replace_bool_expr(edit: &mut SourceChangeBuilder, expr: ast::Expr, make: &SyntaxFactory) {
let expr_range = expr.syntax().text_range();
- let enum_expr = bool_expr_to_enum_expr(expr);
+ let enum_expr = bool_expr_to_enum_expr(expr, make);
edit.replace(expr_range, enum_expr.syntax().text())
}
/// Converts an expression of type `bool` to one of the new enum type.
-fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr {
- let true_expr = make::expr_path(make::path_from_text("Bool::True"));
- let false_expr = make::expr_path(make::path_from_text("Bool::False"));
+fn bool_expr_to_enum_expr(expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr {
+ let true_expr = make.expr_path(make.path_from_text("Bool::True"));
+ let false_expr = make.expr_path(make.path_from_text("Bool::False"));
if let ast::Expr::Literal(literal) = &expr {
match literal.kind() {
@@ -186,10 +196,10 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr {
_ => expr,
}
} else {
- make::expr_if(
+ make.expr_if(
expr,
- make::tail_only_block_expr(true_expr),
- Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))),
+ make.tail_only_block_expr(true_expr),
+ Some(ast::ElseBranch::Block(make.tail_only_block_expr(false_expr))),
)
.into()
}
@@ -203,11 +213,13 @@ fn replace_usages(
target_definition: Definition,
target_module: &hir::Module,
delayed_mutations: &mut Vec<(ImportScope, ast::Path)>,
+ make: &SyntaxFactory,
) {
for (file_id, references) in usages {
edit.edit_file(file_id.file_id(ctx.db()));
- let refs_with_imports = augment_references_with_imports(ctx, references, target_module);
+ let refs_with_imports =
+ augment_references_with_imports(ctx, references, target_module, make);
refs_with_imports.into_iter().rev().for_each(
|FileReferenceWithImport { range, name, import_data }| {
@@ -224,12 +236,13 @@ fn replace_usages(
target_definition,
target_module,
delayed_mutations,
+ make,
)
}
} else if let Some(initializer) = find_assignment_usage(&name) {
cov_mark::hit!(replaces_assignment);
- replace_bool_expr(edit, initializer);
+ replace_bool_expr(edit, initializer, make);
} else if let Some((prefix_expr, inner_expr)) = find_negated_usage(&name) {
cov_mark::hit!(replaces_negation);
@@ -247,7 +260,7 @@ fn replace_usages(
{
cov_mark::hit!(replaces_record_expr);
- let enum_expr = bool_expr_to_enum_expr(initializer);
+ let enum_expr = bool_expr_to_enum_expr(initializer, make);
utils::replace_record_field_expr(ctx, edit, record_field, enum_expr);
} else if let Some(pat) = find_record_pat_field_usage(&name) {
match pat {
@@ -263,6 +276,7 @@ fn replace_usages(
target_definition,
target_module,
delayed_mutations,
+ make,
)
}
}
@@ -272,14 +286,14 @@ fn replace_usages(
if let Some(expr) = literal_pat.literal().and_then(|literal| {
literal.syntax().ancestors().find_map(ast::Expr::cast)
}) {
- replace_bool_expr(edit, expr);
+ replace_bool_expr(edit, expr, make);
}
}
_ => (),
}
} else if let Some((ty_annotation, initializer)) = find_assoc_const_usage(&name) {
edit.replace(ty_annotation.syntax().text_range(), "Bool");
- replace_bool_expr(edit, initializer);
+ replace_bool_expr(edit, initializer, make);
} else if let Some(receiver) = find_method_call_expr_usage(&name) {
edit.replace(
receiver.syntax().text_range(),
@@ -296,10 +310,10 @@ fn replace_usages(
ctx,
edit,
record_field,
- make::expr_bin_op(
+ make.expr_bin_op(
expr,
ast::BinaryOp::CmpOp(ast::CmpOp::Eq { negated: false }),
- make::expr_path(make::path_from_text("Bool::True")),
+ make.expr_path(make.path_from_text("Bool::True")),
),
);
} else {
@@ -327,6 +341,7 @@ fn augment_references_with_imports(
ctx: &AssistContext<'_>,
references: Vec<FileReference>,
target_module: &hir::Module,
+ make: &SyntaxFactory,
) -> Vec<FileReferenceWithImport> {
let mut visited_modules = FxHashSet::default();
@@ -357,9 +372,9 @@ fn augment_references_with_imports(
cfg,
)
.map(|mod_path| {
- make::path_concat(
+ make.path_concat(
mod_path_to_ast(&mod_path, edition),
- make::path_from_text("Bool"),
+ make.path_from_text("Bool"),
)
})?;
@@ -458,6 +473,7 @@ fn add_enum_def(
usages: &UsageSearchResult,
target_node: SyntaxNode,
target_module: &hir::Module,
+ make: &SyntaxFactory,
) -> Option<()> {
let insert_before = node_to_insert_before(target_node);
@@ -482,7 +498,7 @@ fn add_enum_def(
.any(|module| module.nearest_non_block_module(ctx.db()) != *target_module);
let indent = IndentLevel::from_node(&insert_before);
- let enum_def = make_bool_enum(make_enum_pub).reset_indent().indent(indent);
+ let enum_def = make_bool_enum(make_enum_pub, make).reset_indent().indent(indent);
edit.insert(
insert_before.text_range().start(),
@@ -504,31 +520,30 @@ fn node_to_insert_before(target_node: SyntaxNode) -> SyntaxNode {
.unwrap_or(target_node)
}
-fn make_bool_enum(make_pub: bool) -> ast::Enum {
- let derive_eq = make::attr_outer(make::meta_token_tree(
- make::ext::ident_path("derive"),
- make::token_tree(
+fn make_bool_enum(make_pub: bool, make: &SyntaxFactory) -> ast::Enum {
+ let derive_eq = make.attr_outer(make.meta_token_tree(
+ make.ident_path("derive"),
+ make.token_tree(
T!['('],
vec![
- NodeOrToken::Token(make::tokens::ident("PartialEq")),
- NodeOrToken::Token(make::token(T![,])),
- NodeOrToken::Token(make::tokens::single_space()),
- NodeOrToken::Token(make::tokens::ident("Eq")),
+ NodeOrToken::Token(make.ident("PartialEq")),
+ NodeOrToken::Token(make.token(T![,])),
+ NodeOrToken::Token(make.whitespace(" ")),
+ NodeOrToken::Token(make.ident("Eq")),
],
),
));
- make::enum_(
+ make.enum_(
[derive_eq],
- if make_pub { Some(make::visibility_pub()) } else { None },
- make::name("Bool"),
+ if make_pub { Some(make.visibility_pub()) } else { None },
+ make.name("Bool"),
None,
None,
- make::variant_list(vec![
- make::variant(None, make::name("True"), None, None),
- make::variant(None, make::name("False"), None, None),
+ make.variant_list(vec![
+ make.variant(None, make.name("True"), None, None),
+ make.variant(None, make.name("False"), None, None),
]),
)
- .clone_for_update()
}
#[cfg(test)]
diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs
index 769bbd976a..e4fdac27f4 100644
--- a/crates/ide-assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide-assists/src/handlers/extract_type_alias.rs
@@ -2,7 +2,10 @@ use either::Either;
use hir::HirDisplay;
use ide_db::syntax_helpers::node_ext::walk_ty;
use syntax::{
- ast::{self, AstNode, HasGenericArgs, HasGenericParams, HasName, edit::IndentLevel, make},
+ ast::{
+ self, AstNode, HasGenericArgs, HasGenericParams, HasName, edit::IndentLevel,
+ syntax_factory::SyntaxFactory,
+ },
syntax_editor,
};
@@ -43,10 +46,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
let resolved_ty = ctx.sema.resolve_type(&ty)?;
let resolved_ty = if !resolved_ty.contains_unknown() {
let module = ctx.sema.scope(ty.syntax())?.module();
- let resolved_ty = resolved_ty.display_source_code(ctx.db(), module.into(), false).ok()?;
- make::ty(&resolved_ty)
+ resolved_ty.display_source_code(ctx.db(), module.into(), false).ok()?
} else {
- ty.clone()
+ ty.to_string()
};
acc.add(
@@ -55,6 +57,9 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
target,
|builder| {
let mut edit = builder.make_editor(node);
+ let make = SyntaxFactory::without_mappings();
+
+ let resolved_ty = make.ty(&resolved_ty);
let mut known_generics = match item.generic_param_list() {
Some(it) => it.generic_params().collect(),
@@ -68,22 +73,20 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
}
let generics = collect_used_generics(&ty, &known_generics);
let generic_params =
- generics.map(|it| make::generic_param_list(it.into_iter().cloned()));
+ generics.map(|it| make.generic_param_list(it.into_iter().cloned()));
// Replace original type with the alias
let ty_args = generic_params.as_ref().map(|it| it.to_generic_args().generic_args());
let new_ty = if let Some(ty_args) = ty_args {
- make::generic_ty_path_segment(make::name_ref("Type"), ty_args)
+ make.generic_ty_path_segment(make.name_ref("Type"), ty_args)
} else {
- make::path_segment(make::name_ref("Type"))
- }
- .clone_for_update();
+ make.path_segment(make.name_ref("Type"))
+ };
edit.replace(ty.syntax(), new_ty.syntax());
// Insert new alias
let ty_alias =
- make::ty_alias(None, "Type", generic_params, None, None, Some((resolved_ty, None)))
- .clone_for_update();
+ make.ty_alias(None, "Type", generic_params, None, None, Some((resolved_ty, None)));
if let Some(cap) = ctx.config.snippet_cap
&& let Some(name) = ty_alias.name()
@@ -96,7 +99,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
syntax_editor::Position::before(node),
vec![
ty_alias.syntax().clone().into(),
- make::tokens::whitespace(&format!("\n\n{indent}")).into(),
+ make.whitespace(&format!("\n\n{indent}")).into(),
],
);
diff --git a/crates/ide-assists/src/handlers/generate_default_from_new.rs b/crates/ide-assists/src/handlers/generate_default_from_new.rs
index 48400d436a..485184723b 100644
--- a/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -2,7 +2,7 @@ use ide_db::famous_defs::FamousDefs;
use stdx::format_to;
use syntax::{
AstNode,
- ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl, make},
+ ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl, syntax_factory::SyntaxFactory},
};
use crate::{
@@ -72,7 +72,9 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
let default_code = " fn default() -> Self {
Self::new()
}";
- let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code);
+ let make = SyntaxFactory::without_mappings();
+ let code =
+ generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code, &make);
builder.insert(insert_location.end(), code);
},
)
@@ -84,6 +86,7 @@ fn generate_trait_impl_text_from_impl(
self_ty: ast::Type,
trait_text: &str,
code: &str,
+ make: &SyntaxFactory,
) -> String {
let generic_params = impl_.generic_param_list().map(|generic_params| {
let lifetime_params =
@@ -92,18 +95,18 @@ fn generate_trait_impl_text_from_impl(
// remove defaults since they can't be specified in impls
let param = match param {
ast::TypeOrConstParam::Type(param) => {
- let param = make::type_param(param.name()?, param.type_bound_list());
+ let param = make.type_param(param.name()?, param.type_bound_list());
ast::GenericParam::TypeParam(param)
}
ast::TypeOrConstParam::Const(param) => {
- let param = make::const_param(param.name()?, param.ty()?);
+ let param = make.const_param(param.name()?, param.ty()?);
ast::GenericParam::ConstParam(param)
}
};
Some(param)
});
- make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
+ make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
});
let mut buf = String::with_capacity(code.len());
diff --git a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index 7fd94b4bed..6bcbd9b0cc 100644
--- a/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -2,7 +2,7 @@ use either::Either;
use ide_db::assists::{AssistId, GroupLabel};
use syntax::{
AstNode,
- ast::{self, HasGenericParams, HasName, edit::IndentLevel, make},
+ ast::{self, HasGenericParams, HasName, edit::IndentLevel, syntax_factory::SyntaxFactory},
syntax_editor,
};
@@ -56,6 +56,7 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
func_node.syntax().text_range(),
|builder| {
let mut edit = builder.make_editor(func);
+ let make = SyntaxFactory::without_mappings();
let alias_name = format!("{}Fn", stdx::to_camel_case(&name.to_string()));
@@ -68,24 +69,24 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
let is_mut = self_ty.is_mutable_reference();
if let Some(adt) = self_ty.strip_references().as_adt() {
- let inner_type = make::ty(adt.name(ctx.db()).as_str());
+ let inner_type = make.ty(adt.name(ctx.db()).as_str());
let ast_self_ty =
- if is_ref { make::ty_ref(inner_type, is_mut) } else { inner_type };
+ if is_ref { make.ty_ref(inner_type, is_mut) } else { inner_type };
- fn_params_vec.push(make::unnamed_param(ast_self_ty));
+ fn_params_vec.push(make.unnamed_param(ast_self_ty));
}
}
fn_params_vec.extend(param_list.params().filter_map(|p| match style {
ParamStyle::Named => Some(p),
- ParamStyle::Unnamed => p.ty().map(make::unnamed_param),
+ ParamStyle::Unnamed => p.ty().map(|ty| make.unnamed_param(ty)),
}));
let generic_params = func_node.generic_param_list();
let is_unsafe = func_node.unsafe_token().is_some();
- let ty = make::ty_fn_ptr(
+ let ty = make.ty_fn_ptr(
is_unsafe,
func_node.abi(),
fn_params_vec.into_iter(),
@@ -93,22 +94,21 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
);
// Insert new alias
- let ty_alias = make::ty_alias(
+ let ty_alias = make.ty_alias(
None,
&alias_name,
generic_params,
None,
None,
Some((ast::Type::FnPtrType(ty), None)),
- )
- .clone_for_update();
+ );
let indent = IndentLevel::from_node(insertion_node);
edit.insert_all(
syntax_editor::Position::before(insertion_node),
vec![
ty_alias.syntax().clone().into(),
- make::tokens::whitespace(&format!("\n\n{indent}")).into(),
+ make.whitespace(&format!("\n\n{indent}")).into(),
],
);
diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs
index e5425abab0..79b8bd5d3d 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},
- make,
- },
+ ast::{self, AstNode, HasName, HasTypeBounds, syntax_factory::SyntaxFactory},
match_ast,
+ syntax_editor::{GetOrCreateWhereClause, Removable},
};
use crate::{AssistContext, AssistId, Assists};
@@ -47,18 +44,23 @@ 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);
-
- 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(),
+ |builder| {
+ let mut edit = builder.make_editor(&parent);
+ let make = SyntaxFactory::without_mappings();
+
+ let new_preds: Vec<ast::WherePred> = type_param_list
+ .generic_params()
+ .filter_map(|param| build_predicate(param, &make))
+ .collect();
+
+ match_ast! {
+ match (&parent) {
+ ast::Fn(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
+ ast::Trait(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
+ ast::Impl(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
+ ast::Enum(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
+ ast::Struct(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
+ ast::TypeAlias(it) => it.get_or_create_where_clause(&mut edit, &make, new_preds.into_iter()),
_ => return,
}
};
@@ -70,25 +72,22 @@ 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) {
- where_clause.add_predicate(predicate)
- }
- tbl.remove()
+ tbl.remove(&mut edit);
}
}
+
+ builder.add_file_edits(ctx.vfs_file_id(), edit);
},
)
}
-fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> {
+fn build_predicate(param: ast::GenericParam, make: &SyntaxFactory) -> Option<ast::WherePred> {
let target = match &param {
- ast::GenericParam::TypeParam(t) => {
- Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string())))
- }
+ ast::GenericParam::TypeParam(t) => Either::Right(make.ty(&t.name()?.to_string())),
ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?),
ast::GenericParam::ConstParam(_) => return None,
};
- let predicate = make::where_pred(
+ let predicate = make.where_pred(
target,
match param {
ast::GenericParam::TypeParam(t) => t.type_bound_list()?,
@@ -97,7 +96,7 @@ fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> {
}
.bounds(),
);
- Some(predicate.clone_for_update())
+ Some(predicate)
}
#[cfg(test)]
diff --git a/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index df7057835c..018642a047 100644
--- a/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -5,9 +5,10 @@ use ide_db::{
defs::Definition,
search::{SearchScope, UsageSearchResult},
};
+use syntax::ast::syntax_factory::SyntaxFactory;
use syntax::{
AstNode,
- ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType, make},
+ ast::{self, HasGenericParams, HasName, HasTypeBounds, Name, NameLike, PathType},
match_ast,
};
@@ -72,6 +73,7 @@ pub(crate) fn replace_named_generic_with_impl(
target,
|edit| {
let mut editor = edit.make_editor(type_param.syntax());
+ let make = SyntaxFactory::without_mappings();
// remove trait from generic param list
if let Some(generic_params) = fn_.generic_param_list() {
@@ -83,17 +85,14 @@ pub(crate) fn replace_named_generic_with_impl(
if params.is_empty() {
editor.delete(generic_params.syntax());
} else {
- let new_generic_param_list = make::generic_param_list(params);
- editor.replace(
- generic_params.syntax(),
- new_generic_param_list.syntax().clone_for_update(),
- );
+ let new_generic_param_list = make.generic_param_list(params);
+ editor.replace(generic_params.syntax(), new_generic_param_list.syntax());
}
}
- let new_bounds = make::impl_trait_type(type_bound_list);
+ let new_bounds = make.impl_trait_type(type_bound_list);
for path_type in path_types_to_replace.iter().rev() {
- editor.replace(path_type.syntax(), new_bounds.clone_for_update().syntax());
+ editor.replace(path_type.syntax(), new_bounds.syntax());
}
edit.add_file_edits(ctx.vfs_file_id(), editor);
},
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index 27182191c3..50fe565380 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -1,9 +1,11 @@
//! Wrappers over [`make`] constructors
+use either::Either;
+
use crate::{
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
ast::{
self, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
- HasTypeBounds, HasVisibility, RangeItem, make,
+ HasTypeBounds, HasVisibility, Param, RangeItem, make,
},
syntax_editor::SyntaxMappingBuilder,
};
@@ -97,6 +99,52 @@ impl SyntaxFactory {
make::struct_(visibility, strukt_name, generic_param_list, field_list).clone_for_update()
}
+ pub fn enum_(
+ &self,
+ attrs: impl IntoIterator<Item = ast::Attr>,
+ visibility: Option<ast::Visibility>,
+ enum_name: ast::Name,
+ generic_param_list: Option<ast::GenericParamList>,
+ where_clause: Option<ast::WhereClause>,
+ variant_list: ast::VariantList,
+ ) -> ast::Enum {
+ make::enum_(attrs, visibility, enum_name, generic_param_list, where_clause, variant_list)
+ .clone_for_update()
+ }
+
+ pub fn unnamed_param(&self, ty: ast::Type) -> ast::Param {
+ make::unnamed_param(ty).clone_for_update()
+ }
+
+ pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
+ &self,
+ is_unsafe: bool,
+ abi: Option<ast::Abi>,
+ params: I,
+ ret_type: Option<ast::RetType>,
+ ) -> ast::FnPtrType {
+ make::ty_fn_ptr(is_unsafe, abi, params, ret_type).clone_for_update()
+ }
+
+ pub fn where_pred(
+ &self,
+ path: Either<ast::Lifetime, ast::Type>,
+ bounds: impl IntoIterator<Item = ast::TypeBound>,
+ ) -> ast::WherePred {
+ 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 impl_trait_type(&self, bounds: ast::TypeBoundList) -> ast::ImplTraitType {
+ make::impl_trait_type(bounds).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()
@@ -287,6 +335,26 @@ impl SyntaxFactory {
ast
}
+ pub fn generic_ty_path_segment(
+ &self,
+ name_ref: ast::NameRef,
+ generic_args: impl IntoIterator<Item = ast::GenericArg>,
+ ) -> ast::PathSegment {
+ make::generic_ty_path_segment(name_ref, generic_args).clone_for_update()
+ }
+
+ pub fn tail_only_block_expr(&self, tail_expr: ast::Expr) -> ast::BlockExpr {
+ make::tail_only_block_expr(tail_expr)
+ }
+
+ pub fn expr_bin_op(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
+ make::expr_bin_op(lhs, op, rhs)
+ }
+
+ pub fn ty_placeholder(&self) -> ast::Type {
+ make::ty_placeholder().clone_for_update()
+ }
+
pub fn path_segment_generics(
&self,
name_ref: ast::NameRef,
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index 5683d891be..e6937e4d0f 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -20,7 +20,7 @@ mod edit_algo;
mod edits;
mod mapping;
-pub use edits::Removable;
+pub use edits::{GetOrCreateWhereClause, Removable};
pub use mapping::{SyntaxMapping, SyntaxMappingBuilder};
#[derive(Debug)]
diff --git a/crates/syntax/src/syntax_editor/edits.rs b/crates/syntax/src/syntax_editor/edits.rs
index 9090f7c9eb..ad08928923 100644
--- a/crates/syntax/src/syntax_editor/edits.rs
+++ b/crates/syntax/src/syntax_editor/edits.rs
@@ -10,6 +10,107 @@ use crate::{
syntax_editor::{Position, SyntaxEditor},
};
+pub trait GetOrCreateWhereClause: ast::HasGenericParams {
+ fn where_clause_position(&self) -> Option<Position>;
+
+ fn get_or_create_where_clause(
+ &self,
+ editor: &mut SyntaxEditor,
+ make: &SyntaxFactory,
+ new_preds: impl Iterator<Item = ast::WherePred>,
+ ) {
+ let existing = self.where_clause();
+ let all_preds: Vec<_> =
+ existing.iter().flat_map(|wc| wc.predicates()).chain(new_preds).collect();
+ let new_where = make.where_clause(all_preds);
+
+ if let Some(existing) = &existing {
+ editor.replace(existing.syntax(), new_where.syntax());
+ } else if let Some(pos) = self.where_clause_position() {
+ editor.insert_all(
+ pos,
+ vec![make.whitespace(" ").into(), new_where.syntax().clone().into()],
+ );
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::Fn {
+ fn where_clause_position(&self) -> Option<Position> {
+ if let Some(ty) = self.ret_type() {
+ Some(Position::after(ty.syntax()))
+ } else if let Some(param_list) = self.param_list() {
+ Some(Position::after(param_list.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::Impl {
+ fn where_clause_position(&self) -> Option<Position> {
+ if let Some(ty) = self.self_ty() {
+ Some(Position::after(ty.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::Trait {
+ fn where_clause_position(&self) -> Option<Position> {
+ if let Some(gpl) = self.generic_param_list() {
+ Some(Position::after(gpl.syntax()))
+ } else if let Some(name) = self.name() {
+ Some(Position::after(name.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::TypeAlias {
+ fn where_clause_position(&self) -> Option<Position> {
+ if let Some(gpl) = self.generic_param_list() {
+ Some(Position::after(gpl.syntax()))
+ } else if let Some(name) = self.name() {
+ Some(Position::after(name.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::Struct {
+ fn where_clause_position(&self) -> Option<Position> {
+ let tfl = self.field_list().and_then(|fl| match fl {
+ ast::FieldList::RecordFieldList(_) => None,
+ ast::FieldList::TupleFieldList(it) => Some(it),
+ });
+ if let Some(tfl) = tfl {
+ Some(Position::after(tfl.syntax()))
+ } else if let Some(gpl) = self.generic_param_list() {
+ Some(Position::after(gpl.syntax()))
+ } else if let Some(name) = self.name() {
+ Some(Position::after(name.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
+impl GetOrCreateWhereClause for ast::Enum {
+ fn where_clause_position(&self) -> Option<Position> {
+ if let Some(gpl) = self.generic_param_list() {
+ Some(Position::after(gpl.syntax()))
+ } else if let Some(name) = self.name() {
+ Some(Position::after(name.syntax()))
+ } else {
+ Some(Position::last_child_of(self.syntax()))
+ }
+ }
+}
+
impl SyntaxEditor {
/// Adds a new generic param to the function using `SyntaxEditor`
pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) {