mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-11 11:39:44 +00:00
internal: migrate generate_delegate_trait to SyntaxEditor api
This commit is contained in:
parent
80d511fcd8
commit
09e4ad2443
1 changed files with 250 additions and 195 deletions
|
|
@ -14,15 +14,15 @@ use ide_db::{
|
|||
};
|
||||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr,
|
||||
AstNode, Edition, SmolStr, SyntaxElement, SyntaxKind, ToSmolStr,
|
||||
ast::{
|
||||
self, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs,
|
||||
HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path,
|
||||
WherePred,
|
||||
edit::{self, AstNodeEdit},
|
||||
make,
|
||||
syntax_factory::SyntaxFactory,
|
||||
},
|
||||
ted::{self, Position},
|
||||
syntax_editor::SyntaxEditor,
|
||||
};
|
||||
|
||||
// Assist: generate_delegate_trait
|
||||
|
|
@ -169,10 +169,15 @@ enum Delegee {
|
|||
}
|
||||
|
||||
impl Delegee {
|
||||
fn trait_(&self) -> &hir::Trait {
|
||||
match self {
|
||||
Delegee::Bound(it) | Delegee::Impls(it, _) => it,
|
||||
}
|
||||
}
|
||||
|
||||
fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self;
|
||||
let it = self.trait_();
|
||||
|
||||
for m in it.module(db).path_to_root(db).iter().rev() {
|
||||
if let Some(name) = m.name(db) {
|
||||
|
|
@ -201,15 +206,12 @@ impl Struct {
|
|||
let db = ctx.db();
|
||||
|
||||
for (index, delegee) in field.impls.iter().enumerate() {
|
||||
let trait_ = match delegee {
|
||||
Delegee::Bound(b) => b,
|
||||
Delegee::Impls(i, _) => i,
|
||||
};
|
||||
let trait_ = delegee.trait_();
|
||||
|
||||
// Skip trait that has `Self` type, which cannot be delegated
|
||||
//
|
||||
// See [`test_self_ty`]
|
||||
if has_self_type(*trait_, ctx).is_some() {
|
||||
if has_self_type(*trait_, ctx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -254,9 +256,10 @@ fn generate_impl(
|
|||
delegee: &Delegee,
|
||||
edition: Edition,
|
||||
) -> Option<ast::Impl> {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let db = ctx.db();
|
||||
let ast_strukt = &strukt.strukt;
|
||||
let strukt_ty = make::ty_path(make::ext::ident_path(&strukt.name.to_string()));
|
||||
let strukt_ty = make.ty_path(make.ident_path(&strukt.name.to_string())).into();
|
||||
let strukt_params = ast_strukt.generic_param_list();
|
||||
|
||||
match delegee {
|
||||
|
|
@ -264,7 +267,7 @@ fn generate_impl(
|
|||
let bound_def = ctx.sema.source(delegee.to_owned())?.value;
|
||||
let bound_params = bound_def.generic_param_list();
|
||||
|
||||
let delegate = make::impl_trait(
|
||||
let delegate = make.impl_trait(
|
||||
None,
|
||||
delegee.is_unsafe(db),
|
||||
bound_params.clone(),
|
||||
|
|
@ -272,33 +275,28 @@ fn generate_impl(
|
|||
strukt_params.clone(),
|
||||
strukt_params.map(|params| params.to_generic_args()),
|
||||
delegee.is_auto(db),
|
||||
make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
|
||||
make.ty(&delegee.name(db).display_no_db(edition).to_smolstr()),
|
||||
strukt_ty,
|
||||
bound_def.where_clause(),
|
||||
ast_strukt.where_clause(),
|
||||
None,
|
||||
)
|
||||
.clone_for_update();
|
||||
);
|
||||
|
||||
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
|
||||
let qualified_path_type =
|
||||
make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
||||
make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
||||
|
||||
let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
|
||||
if let Some(ai) = bound_def.assoc_item_list() {
|
||||
// Collect assoc items
|
||||
let assoc_items: Option<Vec<ast::AssocItem>> = bound_def.assoc_item_list().map(|ai| {
|
||||
ai.assoc_items()
|
||||
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
|
||||
.for_each(|item| {
|
||||
let assoc = process_assoc_item(
|
||||
item.clone_for_update(),
|
||||
qualified_path_type.clone(),
|
||||
field_name,
|
||||
);
|
||||
if let Some(assoc) = assoc {
|
||||
delegate_assoc_items.add_item(assoc);
|
||||
}
|
||||
});
|
||||
};
|
||||
.filter_map(|item| {
|
||||
process_assoc_item(item, qualified_path_type.clone(), field_name)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
let delegate = finalize_delegate(&delegate, assoc_items, false)?;
|
||||
|
||||
let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
|
||||
let source_scope = ctx.sema.scope(bound_def.syntax())?;
|
||||
|
|
@ -324,7 +322,7 @@ fn generate_impl(
|
|||
.and_then(|wc| rename_strukt_args(ctx, ast_strukt, &wc, &args));
|
||||
(field_ty, where_clause)
|
||||
}
|
||||
None => (field_ty.clone_for_update(), None),
|
||||
None => (field_ty.clone(), None),
|
||||
};
|
||||
|
||||
// 2) Handle instantiated generics in `field_ty`.
|
||||
|
|
@ -347,38 +345,38 @@ fn generate_impl(
|
|||
);
|
||||
|
||||
// 2.2) Generate generic args applied on impl.
|
||||
let transform_args = generate_args_for_impl(
|
||||
let (transform_args, trait_gen_params) = generate_args_for_impl(
|
||||
old_impl_params,
|
||||
&old_impl.self_ty()?,
|
||||
&field_ty,
|
||||
&trait_gen_params,
|
||||
trait_gen_params,
|
||||
&old_impl_trait_args,
|
||||
);
|
||||
|
||||
// 2.3) Instantiate generics with `transform_impl`, this step also
|
||||
// remove unused params.
|
||||
let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| {
|
||||
let trait_args = &mut trait_args.clone_for_update();
|
||||
if let Some(new_args) = transform_impl(
|
||||
ctx,
|
||||
ast_strukt,
|
||||
&old_impl,
|
||||
&transform_args,
|
||||
trait_args.clone_subtree(),
|
||||
) {
|
||||
*trait_args = new_args.clone_subtree();
|
||||
Some(new_args)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let trait_gen_args =
|
||||
old_impl.trait_()?.generic_arg_list().and_then(|mut trait_args| {
|
||||
let trait_args = &mut trait_args;
|
||||
if let Some(new_args) = transform_impl(
|
||||
ctx,
|
||||
ast_strukt,
|
||||
&old_impl,
|
||||
&transform_args,
|
||||
trait_args.clone_subtree(),
|
||||
) {
|
||||
*trait_args = new_args.clone_subtree();
|
||||
Some(new_args)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
|
||||
let path_type =
|
||||
make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
|
||||
let path_type = make.ty(&trait_.name(db).display_no_db(edition).to_smolstr());
|
||||
let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
|
||||
// 3) Generate delegate trait impl
|
||||
let delegate = make::impl_trait(
|
||||
let delegate = make.impl_trait(
|
||||
None,
|
||||
trait_.is_unsafe(db),
|
||||
trait_gen_params,
|
||||
|
|
@ -388,34 +386,27 @@ fn generate_impl(
|
|||
trait_.is_auto(db),
|
||||
path_type,
|
||||
strukt_ty,
|
||||
old_impl.where_clause().map(|wc| wc.clone_for_update()),
|
||||
old_impl.where_clause(),
|
||||
ty_where_clause,
|
||||
None,
|
||||
)
|
||||
.clone_for_update();
|
||||
);
|
||||
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
|
||||
let qualified_path_type =
|
||||
make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
||||
make.path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
||||
|
||||
// 4) Transform associated items in delegte trait impl
|
||||
let delegate_assoc_items = delegate.get_or_create_assoc_item_list();
|
||||
for item in old_impl
|
||||
.get_or_create_assoc_item_list()
|
||||
.assoc_items()
|
||||
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
|
||||
{
|
||||
let item = item.clone_for_update();
|
||||
let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
|
||||
// 4) Transform associated items in delegate trait impl
|
||||
let assoc_items: Option<Vec<ast::AssocItem>> = old_impl.assoc_item_list().map(|ail| {
|
||||
ail.assoc_items()
|
||||
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
|
||||
.filter_map(|item| {
|
||||
let item =
|
||||
transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
|
||||
process_assoc_item(item, qualified_path_type.clone(), field_name)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
|
||||
delegate_assoc_items.add_item(assoc);
|
||||
}
|
||||
|
||||
// 5) Remove useless where clauses
|
||||
if let Some(wc) = delegate.where_clause() {
|
||||
remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
|
||||
}
|
||||
Some(delegate)
|
||||
finalize_delegate(&delegate, assoc_items, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -446,6 +437,35 @@ fn transform_impl<N: ast::AstNode>(
|
|||
N::cast(transform.apply(syntax.syntax()))
|
||||
}
|
||||
|
||||
/// Extracts the name from a generic parameter.
|
||||
fn generic_param_name(param: &ast::GenericParam) -> Option<String> {
|
||||
match param {
|
||||
ast::GenericParam::TypeParam(t) => t.name().map(|n| n.to_string()),
|
||||
ast::GenericParam::ConstParam(c) => c.name().map(|n| n.to_string()),
|
||||
ast::GenericParam::LifetimeParam(l) => l.lifetime().map(|lt| lt.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Filters generic params, keeping only those whose names are not in `names_to_remove`.
|
||||
fn filter_generic_params(
|
||||
gpl: ast::GenericParamList,
|
||||
names_to_remove: &FxHashSet<String>,
|
||||
) -> Option<ast::GenericParamList> {
|
||||
let remaining_params: Vec<_> = gpl
|
||||
.generic_params()
|
||||
.filter(|param| {
|
||||
generic_param_name(param).is_none_or(|name| !names_to_remove.contains(&name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if remaining_params.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
Some(make.generic_param_list(remaining_params))
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_instantiated_params(
|
||||
self_ty: &ast::Type,
|
||||
old_impl_params: Option<GenericParamList>,
|
||||
|
|
@ -454,10 +474,8 @@ fn remove_instantiated_params(
|
|||
match self_ty {
|
||||
ast::Type::PathType(path_type) => {
|
||||
old_impl_params.and_then(|gpl| {
|
||||
// Remove generic parameters in field_ty (which is instantiated).
|
||||
let new_gpl = gpl.clone_for_update();
|
||||
|
||||
path_type
|
||||
// Collect generic args that should be removed (instantiated params)
|
||||
let args_to_remove: FxHashSet<String> = path_type
|
||||
.path()?
|
||||
.segments()
|
||||
.filter_map(|seg| seg.generic_arg_list())
|
||||
|
|
@ -466,16 +484,25 @@ fn remove_instantiated_params(
|
|||
// it shouldn't be removed now, which will be instantiated in
|
||||
// later `path_transform`
|
||||
.filter(|arg| !old_trait_args.contains(&arg.to_string()))
|
||||
.for_each(|arg| new_gpl.remove_generic_arg(&arg));
|
||||
(new_gpl.generic_params().count() > 0).then_some(new_gpl)
|
||||
.map(|arg| arg.to_string())
|
||||
.collect();
|
||||
|
||||
filter_generic_params(gpl, &args_to_remove)
|
||||
})
|
||||
}
|
||||
_ => old_impl_params,
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: ast::WhereClause) {
|
||||
let live_generics = [trait_ty, self_ty]
|
||||
fn remove_useless_where_clauses(editor: &mut SyntaxEditor, delegate: &ast::Impl) {
|
||||
let Some(wc) = delegate.where_clause() else {
|
||||
return;
|
||||
};
|
||||
let (Some(trait_ty), Some(self_ty)) = (delegate.trait_(), delegate.self_ty()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let live_generics = [&trait_ty, &self_ty]
|
||||
.into_iter()
|
||||
.flat_map(|ty| ty.generic_arg_list())
|
||||
.flat_map(|gal| gal.generic_args())
|
||||
|
|
@ -484,36 +511,78 @@ fn remove_useless_where_clauses(trait_ty: &ast::Type, self_ty: &ast::Type, wc: a
|
|||
|
||||
// Keep where-clauses that have generics after substitution, and remove the
|
||||
// rest.
|
||||
let has_live_generics = |pred: &WherePred| {
|
||||
let has_no_live_generics = |pred: &WherePred| {
|
||||
pred.syntax()
|
||||
.descendants_with_tokens()
|
||||
.filter_map(|e| e.into_token())
|
||||
.any(|e| e.kind() == SyntaxKind::IDENT && live_generics.contains(&e.to_string()))
|
||||
.not()
|
||||
};
|
||||
wc.predicates().filter(has_live_generics).for_each(|pred| wc.remove_predicate(pred));
|
||||
|
||||
if wc.predicates().count() == 0 {
|
||||
// Remove useless whitespaces
|
||||
[syntax::Direction::Prev, syntax::Direction::Next]
|
||||
.into_iter()
|
||||
.flat_map(|dir| {
|
||||
wc.syntax()
|
||||
.siblings_with_tokens(dir)
|
||||
.skip(1)
|
||||
.take_while(|node_or_tok| node_or_tok.kind() == SyntaxKind::WHITESPACE)
|
||||
})
|
||||
.for_each(ted::remove);
|
||||
let predicates_to_remove: Vec<_> = wc.predicates().filter(has_no_live_generics).collect();
|
||||
let remaining_predicates = wc.predicates().count() - predicates_to_remove.len();
|
||||
|
||||
ted::insert(
|
||||
ted::Position::after(wc.syntax()),
|
||||
NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
|
||||
);
|
||||
// Remove where clause
|
||||
ted::remove(wc.syntax());
|
||||
if remaining_predicates == 0 {
|
||||
// Remove the entire where clause
|
||||
editor.delete(wc.syntax().clone());
|
||||
} else {
|
||||
// Remove only the useless predicates
|
||||
for pred in predicates_to_remove {
|
||||
// Also remove the comma before or after the predicate
|
||||
if let Some(previous) = pred.syntax().prev_sibling() {
|
||||
// Remove from after previous sibling to predicate (inclusive)
|
||||
if let Some(start) = previous.next_sibling_or_token() {
|
||||
let end: SyntaxElement = pred.syntax().clone().into();
|
||||
editor.delete_all(start..=end);
|
||||
}
|
||||
} else if let Some(next) = pred.syntax().next_sibling() {
|
||||
// Remove from predicate to before next sibling (exclusive)
|
||||
if let Some(end) = next.prev_sibling_or_token() {
|
||||
let start: SyntaxElement = pred.syntax().clone().into();
|
||||
editor.delete_all(start..=end);
|
||||
}
|
||||
} else {
|
||||
editor.delete(pred.syntax().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalize the delegate impl by:
|
||||
/// 1. Replacing the assoc_item_list with new items (if any)
|
||||
/// 2. Removing useless where clauses
|
||||
fn finalize_delegate(
|
||||
delegate: &ast::Impl,
|
||||
assoc_items: Option<Vec<ast::AssocItem>>,
|
||||
remove_where_clauses: bool,
|
||||
) -> Option<ast::Impl> {
|
||||
let has_items = assoc_items.as_ref().is_some_and(|items| !items.is_empty());
|
||||
|
||||
if !has_items && !remove_where_clauses {
|
||||
return Some(delegate.clone());
|
||||
}
|
||||
|
||||
let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
|
||||
|
||||
// 1. Replace assoc_item_list if we have new items
|
||||
if let Some(items) = assoc_items
|
||||
&& !items.is_empty()
|
||||
{
|
||||
let new_assoc_item_list =
|
||||
syntax::ast::make::assoc_item_list(Some(items)).clone_for_update();
|
||||
if let Some(old_list) = delegate.assoc_item_list() {
|
||||
editor.replace(old_list.syntax(), new_assoc_item_list.syntax());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Remove useless where clauses
|
||||
if remove_where_clauses {
|
||||
remove_useless_where_clauses(&mut editor, delegate);
|
||||
}
|
||||
|
||||
ast::Impl::cast(editor.finish().new_root().clone())
|
||||
}
|
||||
|
||||
// Generate generic args that should be apply to current impl.
|
||||
//
|
||||
// For example, say we have implementation `impl<A, B, C> Trait for B<A>`,
|
||||
|
|
@ -524,10 +593,13 @@ fn generate_args_for_impl(
|
|||
old_impl_gpl: Option<GenericParamList>,
|
||||
self_ty: &ast::Type,
|
||||
field_ty: &ast::Type,
|
||||
trait_params: &Option<GenericParamList>,
|
||||
trait_params: Option<GenericParamList>,
|
||||
old_trait_args: &FxHashSet<String>,
|
||||
) -> Option<ast::GenericArgList> {
|
||||
let old_impl_args = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args())?;
|
||||
) -> (Option<ast::GenericArgList>, Option<GenericParamList>) {
|
||||
let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else {
|
||||
return (None, trait_params);
|
||||
};
|
||||
|
||||
// Create pairs of the args of `self_ty` and corresponding `field_ty` to
|
||||
// form the substitution list
|
||||
let mut arg_substs = FxHashMap::default();
|
||||
|
|
@ -542,6 +614,8 @@ fn generate_args_for_impl(
|
|||
}
|
||||
}
|
||||
|
||||
let mut params_to_remove = FxHashSet::default();
|
||||
|
||||
let args = old_impl_args
|
||||
.map(|old_arg| {
|
||||
arg_substs.get(&old_arg.to_string()).map_or_else(
|
||||
|
|
@ -549,14 +623,18 @@ fn generate_args_for_impl(
|
|||
|replace_with| {
|
||||
// The old_arg will be replaced, so it becomes redundant
|
||||
if trait_params.is_some() && old_trait_args.contains(&old_arg.to_string()) {
|
||||
trait_params.as_ref().unwrap().remove_generic_arg(&old_arg)
|
||||
params_to_remove.insert(old_arg.to_string());
|
||||
}
|
||||
replace_with.clone()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
args.is_empty().not().then(|| make::generic_arg_list(args))
|
||||
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let result = args.is_empty().not().then(|| make.generic_arg_list(args, false));
|
||||
let trait_params = trait_params.and_then(|gpl| filter_generic_params(gpl, ¶ms_to_remove));
|
||||
(result, trait_params)
|
||||
}
|
||||
|
||||
fn rename_strukt_args<N>(
|
||||
|
|
@ -570,41 +648,37 @@ where
|
|||
{
|
||||
let hir_strukt = ctx.sema.to_struct_def(strukt)?;
|
||||
let hir_adt = hir::Adt::from(hir_strukt);
|
||||
|
||||
let item = item.clone_for_update();
|
||||
let scope = ctx.sema.scope(item.syntax())?;
|
||||
|
||||
let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
|
||||
N::cast(transform.apply(item.syntax()))
|
||||
}
|
||||
|
||||
fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let trait_source = ctx.sema.source(trait_)?.value;
|
||||
trait_source
|
||||
.syntax()
|
||||
.descendants_with_tokens()
|
||||
.filter_map(|e| e.into_token())
|
||||
.find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
|
||||
.map(|_| ())
|
||||
fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> bool {
|
||||
ctx.sema
|
||||
.source(trait_)
|
||||
.and_then(|src| {
|
||||
src.value
|
||||
.syntax()
|
||||
.descendants_with_tokens()
|
||||
.filter_map(|e| e.into_token())
|
||||
.find(|e| e.kind() == SyntaxKind::SELF_TYPE_KW)
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn resolve_name_conflicts(
|
||||
strukt_params: Option<ast::GenericParamList>,
|
||||
old_impl_params: &Option<ast::GenericParamList>,
|
||||
) -> Option<ast::GenericParamList> {
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
match (strukt_params, old_impl_params) {
|
||||
(Some(old_strukt_params), Some(old_impl_params)) => {
|
||||
let params = make::generic_param_list(std::iter::empty()).clone_for_update();
|
||||
let mut new_params: Vec<ast::GenericParam> = Vec::new();
|
||||
|
||||
for old_strukt_param in old_strukt_params.generic_params() {
|
||||
// Get old name from `strukt`
|
||||
let name = SmolStr::from(match &old_strukt_param {
|
||||
ast::GenericParam::ConstParam(c) => c.name()?.to_string(),
|
||||
ast::GenericParam::LifetimeParam(l) => {
|
||||
l.lifetime()?.lifetime_ident_token()?.to_string()
|
||||
}
|
||||
ast::GenericParam::TypeParam(t) => t.name()?.to_string(),
|
||||
});
|
||||
let name = SmolStr::from(generic_param_name(&old_strukt_param)?);
|
||||
|
||||
// The new name cannot be conflicted with generics in trait, and the renamed names.
|
||||
let param_list_to_names = |param_list: &GenericParamList| {
|
||||
|
|
@ -613,8 +687,9 @@ fn resolve_name_conflicts(
|
|||
p => Some(p.to_string()),
|
||||
})
|
||||
};
|
||||
let new_params_list = make.generic_param_list(new_params.clone());
|
||||
let existing_names = param_list_to_names(old_impl_params)
|
||||
.chain(param_list_to_names(¶ms))
|
||||
.chain(param_list_to_names(&new_params_list))
|
||||
.collect_vec();
|
||||
let mut name_generator = suggest_name::NameGenerator::new_with_names(
|
||||
existing_names.iter().map(|s| s.as_str()),
|
||||
|
|
@ -623,25 +698,21 @@ fn resolve_name_conflicts(
|
|||
match old_strukt_param {
|
||||
ast::GenericParam::ConstParam(c) => {
|
||||
if let Some(const_ty) = c.ty() {
|
||||
let const_param = make::const_param(make::name(&name), const_ty);
|
||||
params.add_generic_param(ast::GenericParam::ConstParam(
|
||||
const_param.clone_for_update(),
|
||||
));
|
||||
let const_param = make.const_param(make.name(&name), const_ty);
|
||||
new_params.push(ast::GenericParam::ConstParam(const_param));
|
||||
}
|
||||
}
|
||||
p @ ast::GenericParam::LifetimeParam(_) => {
|
||||
params.add_generic_param(p.clone_for_update());
|
||||
new_params.push(p.clone_for_update());
|
||||
}
|
||||
ast::GenericParam::TypeParam(t) => {
|
||||
let type_bounds = t.type_bound_list();
|
||||
let type_param = make::type_param(make::name(&name), type_bounds);
|
||||
params.add_generic_param(ast::GenericParam::TypeParam(
|
||||
type_param.clone_for_update(),
|
||||
));
|
||||
let type_param = make.type_param(make.name(&name), type_bounds);
|
||||
new_params.push(ast::GenericParam::TypeParam(type_param));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(params)
|
||||
Some(make.generic_param_list(new_params))
|
||||
}
|
||||
(Some(old_strukt_gpl), None) => Some(old_strukt_gpl),
|
||||
_ => None,
|
||||
|
|
@ -666,7 +737,8 @@ fn process_assoc_item(
|
|||
}
|
||||
|
||||
fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
|
||||
let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
|
||||
|
||||
// We want rhs of the const assignment to be a qualified path
|
||||
// The general case for const assignment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`)
|
||||
|
|
@ -674,15 +746,14 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option
|
|||
// <Base as Trait<GenArgs>>::ConstName;
|
||||
// FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it.
|
||||
// make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
|
||||
let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
|
||||
let inner = make::item_const(
|
||||
let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
|
||||
let inner = make.item_const(
|
||||
item.attrs(),
|
||||
item.visibility(),
|
||||
item.name()?,
|
||||
item.ty()?,
|
||||
make::expr_path(qualified_path),
|
||||
)
|
||||
.clone_for_update();
|
||||
make.expr_path(qualified_path),
|
||||
);
|
||||
|
||||
Some(AssocItem::Const(inner))
|
||||
}
|
||||
|
|
@ -692,59 +763,46 @@ fn func_assoc_item(
|
|||
qual_path_ty: Path,
|
||||
base_name: &str,
|
||||
) -> Option<AssocItem> {
|
||||
let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
|
||||
let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
|
||||
let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
|
||||
|
||||
let call = match item.param_list() {
|
||||
// Methods and funcs should be handled separately.
|
||||
// We ask if the func has a `self` param.
|
||||
Some(l) => match l.self_param() {
|
||||
Some(slf) => {
|
||||
let mut self_kw = make::expr_path(make::path_from_text("self"));
|
||||
self_kw = make::expr_field(self_kw, base_name);
|
||||
let self_kw = make.expr_path(make.path_from_text("self"));
|
||||
let self_kw = make.expr_field(self_kw, base_name).into();
|
||||
|
||||
let tail_expr_self = match slf.kind() {
|
||||
ast::SelfParamKind::Owned => self_kw,
|
||||
ast::SelfParamKind::Ref => make::expr_ref(self_kw, false),
|
||||
ast::SelfParamKind::MutRef => make::expr_ref(self_kw, true),
|
||||
ast::SelfParamKind::Ref => make.expr_ref(self_kw, false),
|
||||
ast::SelfParamKind::MutRef => make.expr_ref(self_kw, true),
|
||||
};
|
||||
|
||||
let param_count = l.params().count();
|
||||
let args = convert_param_list_to_arg_list(l).clone_for_update();
|
||||
let pos_after_l_paren = Position::after(args.l_paren_token()?);
|
||||
if param_count > 0 {
|
||||
// Add SelfParam and a TOKEN::COMMA
|
||||
ted::insert_all_raw(
|
||||
pos_after_l_paren,
|
||||
vec![
|
||||
NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
|
||||
NodeOrToken::Token(make::token(SyntaxKind::COMMA)),
|
||||
NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
// Add SelfParam only
|
||||
ted::insert_raw(
|
||||
pos_after_l_paren,
|
||||
NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
|
||||
);
|
||||
}
|
||||
// Build argument list with self expression prepended
|
||||
let other_args = convert_param_list_to_arg_list(l);
|
||||
let all_args: Vec<ast::Expr> =
|
||||
std::iter::once(tail_expr_self).chain(other_args.args()).collect();
|
||||
let args = make.arg_list(all_args);
|
||||
|
||||
make::expr_call(make::expr_path(qualified_path), args)
|
||||
}
|
||||
None => {
|
||||
make::expr_call(make::expr_path(qualified_path), convert_param_list_to_arg_list(l))
|
||||
make.expr_call(make.expr_path(qualified_path), args).into()
|
||||
}
|
||||
None => make
|
||||
.expr_call(make.expr_path(qualified_path), convert_param_list_to_arg_list(l))
|
||||
.into(),
|
||||
},
|
||||
None => make::expr_call(
|
||||
make::expr_path(qualified_path),
|
||||
convert_param_list_to_arg_list(make::param_list(None, Vec::new())),
|
||||
),
|
||||
}
|
||||
.clone_for_update();
|
||||
None => make
|
||||
.expr_call(
|
||||
make.expr_path(qualified_path),
|
||||
convert_param_list_to_arg_list(make.param_list(None, Vec::new())),
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
|
||||
let body = make::block_expr(vec![], Some(call.into())).clone_for_update();
|
||||
let func = make::fn_(
|
||||
let body = make.block_expr(vec![], Some(call));
|
||||
let func = make.fn_(
|
||||
item.attrs(),
|
||||
item.visibility(),
|
||||
item.name()?,
|
||||
|
|
@ -757,35 +815,32 @@ fn func_assoc_item(
|
|||
item.const_token().is_some(),
|
||||
item.unsafe_token().is_some(),
|
||||
item.gen_token().is_some(),
|
||||
)
|
||||
.clone_for_update();
|
||||
);
|
||||
|
||||
Some(AssocItem::Fn(func.indent(edit::IndentLevel(1))))
|
||||
}
|
||||
|
||||
fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
|
||||
let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
|
||||
let qualified_path = qualified_path(qual_path_ty, path_expr_segment);
|
||||
let ty = make::ty_path(qualified_path);
|
||||
let make = SyntaxFactory::without_mappings();
|
||||
let path_expr_segment = make.path_from_text(item.name()?.to_string().as_str());
|
||||
let qualified_path = make.path_from_text(&format!("{qual_path_ty}::{path_expr_segment}"));
|
||||
let ty = make.ty_path(qualified_path).into();
|
||||
let ident = item.name()?.to_string();
|
||||
|
||||
let alias = make::ty_alias(
|
||||
item.attrs(),
|
||||
ident.as_str(),
|
||||
item.generic_param_list(),
|
||||
None,
|
||||
item.where_clause(),
|
||||
Some((ty, None)),
|
||||
)
|
||||
.indent(edit::IndentLevel(1));
|
||||
let alias = make
|
||||
.ty_alias(
|
||||
item.attrs(),
|
||||
ident.as_str(),
|
||||
item.generic_param_list(),
|
||||
None,
|
||||
item.where_clause(),
|
||||
Some((ty, None)),
|
||||
)
|
||||
.indent(edit::IndentLevel(1));
|
||||
|
||||
Some(AssocItem::TypeAlias(alias))
|
||||
}
|
||||
|
||||
fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
|
||||
make::path_from_text(&format!("{qual_path_ty}::{path_expr_seg}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue