mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
Merge pull request #20303 from Hmikihiro/migrate_path_transform
Migrate path transform
This commit is contained in:
commit
3a0cf54236
@ -16,8 +16,9 @@ use syntax::{
|
|||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, T,
|
SyntaxNode, T,
|
||||||
ast::{
|
ast::{
|
||||||
self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::IndentLevel,
|
self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility,
|
||||||
edit_in_place::Indent, make,
|
edit::{AstNodeEdit, IndentLevel},
|
||||||
|
make,
|
||||||
},
|
},
|
||||||
match_ast, ted,
|
match_ast, ted,
|
||||||
};
|
};
|
||||||
@ -110,20 +111,30 @@ pub(crate) fn extract_struct_from_enum_variant(
|
|||||||
let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
|
let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
|
||||||
|
|
||||||
// resolve GenericArg in field_list to actual type
|
// resolve GenericArg in field_list to actual type
|
||||||
let field_list = field_list.clone_for_update();
|
let field_list = if let Some((target_scope, source_scope)) =
|
||||||
if let Some((target_scope, source_scope)) =
|
|
||||||
ctx.sema.scope(enum_ast.syntax()).zip(ctx.sema.scope(field_list.syntax()))
|
ctx.sema.scope(enum_ast.syntax()).zip(ctx.sema.scope(field_list.syntax()))
|
||||||
{
|
{
|
||||||
|
let field_list = field_list.reset_indent();
|
||||||
|
let field_list =
|
||||||
PathTransform::generic_transformation(&target_scope, &source_scope)
|
PathTransform::generic_transformation(&target_scope, &source_scope)
|
||||||
.apply(field_list.syntax());
|
.apply(field_list.syntax());
|
||||||
|
match_ast! {
|
||||||
|
match field_list {
|
||||||
|
ast::RecordFieldList(field_list) => Either::Left(field_list),
|
||||||
|
ast::TupleFieldList(field_list) => Either::Right(field_list),
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field_list.clone_for_update()
|
||||||
|
};
|
||||||
|
|
||||||
let def =
|
let def =
|
||||||
create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
|
create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
|
||||||
|
|
||||||
let enum_ast = variant.parent_enum();
|
let enum_ast = variant.parent_enum();
|
||||||
let indent = enum_ast.indent_level();
|
let indent = enum_ast.indent_level();
|
||||||
def.reindent_to(indent);
|
let def = def.indent(indent);
|
||||||
|
|
||||||
ted::insert_all(
|
ted::insert_all(
|
||||||
ted::Position::before(enum_ast.syntax()),
|
ted::Position::before(enum_ast.syntax()),
|
||||||
@ -279,7 +290,7 @@ fn create_struct_def(
|
|||||||
field_list.clone().into()
|
field_list.clone().into()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
field_list.reindent_to(IndentLevel::single());
|
let field_list = field_list.indent(IndentLevel::single());
|
||||||
|
|
||||||
let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
|
let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
|
||||||
|
|
||||||
|
@ -114,10 +114,14 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|
|||||||
let source_scope = ctx.sema.scope(v.syntax());
|
let source_scope = ctx.sema.scope(v.syntax());
|
||||||
let target_scope = ctx.sema.scope(strukt.syntax());
|
let target_scope = ctx.sema.scope(strukt.syntax());
|
||||||
if let (Some(s), Some(t)) = (source_scope, target_scope) {
|
if let (Some(s), Some(t)) = (source_scope, target_scope) {
|
||||||
PathTransform::generic_transformation(&t, &s).apply(v.syntax());
|
ast::Fn::cast(
|
||||||
}
|
PathTransform::generic_transformation(&t, &s).apply(v.syntax()),
|
||||||
|
)
|
||||||
|
.unwrap_or(v)
|
||||||
|
} else {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,7 +255,6 @@ fn generate_impl(
|
|||||||
delegee: &Delegee,
|
delegee: &Delegee,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
) -> Option<ast::Impl> {
|
) -> Option<ast::Impl> {
|
||||||
let delegate: ast::Impl;
|
|
||||||
let db = ctx.db();
|
let db = ctx.db();
|
||||||
let ast_strukt = &strukt.strukt;
|
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::ext::ident_path(&strukt.name.to_string()));
|
||||||
@ -266,7 +265,7 @@ fn generate_impl(
|
|||||||
let bound_def = ctx.sema.source(delegee.to_owned())?.value;
|
let bound_def = ctx.sema.source(delegee.to_owned())?.value;
|
||||||
let bound_params = bound_def.generic_param_list();
|
let bound_params = bound_def.generic_param_list();
|
||||||
|
|
||||||
delegate = make::impl_trait(
|
let delegate = make::impl_trait(
|
||||||
delegee.is_unsafe(db),
|
delegee.is_unsafe(db),
|
||||||
bound_params.clone(),
|
bound_params.clone(),
|
||||||
bound_params.map(|params| params.to_generic_args()),
|
bound_params.map(|params| params.to_generic_args()),
|
||||||
@ -304,7 +303,7 @@ fn generate_impl(
|
|||||||
let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
|
let target_scope = ctx.sema.scope(strukt.strukt.syntax())?;
|
||||||
let source_scope = ctx.sema.scope(bound_def.syntax())?;
|
let source_scope = ctx.sema.scope(bound_def.syntax())?;
|
||||||
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
|
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
|
||||||
transform.apply(delegate.syntax());
|
ast::Impl::cast(transform.apply(delegate.syntax()))
|
||||||
}
|
}
|
||||||
Delegee::Impls(trait_, old_impl) => {
|
Delegee::Impls(trait_, old_impl) => {
|
||||||
let old_impl = ctx.sema.source(old_impl.to_owned())?.value;
|
let old_impl = ctx.sema.source(old_impl.to_owned())?.value;
|
||||||
@ -358,20 +357,28 @@ fn generate_impl(
|
|||||||
|
|
||||||
// 2.3) Instantiate generics with `transform_impl`, this step also
|
// 2.3) Instantiate generics with `transform_impl`, this step also
|
||||||
// remove unused params.
|
// remove unused params.
|
||||||
let mut trait_gen_args = old_impl.trait_()?.generic_arg_list();
|
let trait_gen_args = old_impl.trait_()?.generic_arg_list().and_then(|trait_args| {
|
||||||
if let Some(trait_args) = &mut trait_gen_args {
|
let trait_args = &mut trait_args.clone_for_update();
|
||||||
*trait_args = trait_args.clone_for_update();
|
if let Some(new_args) = transform_impl(
|
||||||
transform_impl(ctx, ast_strukt, &old_impl, &transform_args, trait_args.syntax())?;
|
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 type_gen_args = strukt_params.clone().map(|params| params.to_generic_args());
|
||||||
|
|
||||||
let path_type =
|
let path_type =
|
||||||
make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
|
make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update();
|
||||||
transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?;
|
let path_type = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type)?;
|
||||||
|
|
||||||
// 3) Generate delegate trait impl
|
// 3) Generate delegate trait impl
|
||||||
delegate = make::impl_trait(
|
let delegate = make::impl_trait(
|
||||||
trait_.is_unsafe(db),
|
trait_.is_unsafe(db),
|
||||||
trait_gen_params,
|
trait_gen_params,
|
||||||
trait_gen_args,
|
trait_gen_args,
|
||||||
@ -385,7 +392,6 @@ fn generate_impl(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.clone_for_update();
|
.clone_for_update();
|
||||||
|
|
||||||
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
|
// Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths
|
||||||
let qualified_path_type =
|
let qualified_path_type =
|
||||||
make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
make::path_from_text(&format!("<{} as {}>", field_ty, delegate.trait_()?));
|
||||||
@ -398,7 +404,7 @@ fn generate_impl(
|
|||||||
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
|
.filter(|item| matches!(item, AssocItem::MacroCall(_)).not())
|
||||||
{
|
{
|
||||||
let item = item.clone_for_update();
|
let item = item.clone_for_update();
|
||||||
transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item.syntax())?;
|
let item = transform_impl(ctx, ast_strukt, &old_impl, &transform_args, item)?;
|
||||||
|
|
||||||
let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
|
let assoc = process_assoc_item(item, qualified_path_type.clone(), field_name)?;
|
||||||
delegate_assoc_items.add_item(assoc);
|
delegate_assoc_items.add_item(assoc);
|
||||||
@ -408,19 +414,18 @@ fn generate_impl(
|
|||||||
if let Some(wc) = delegate.where_clause() {
|
if let Some(wc) = delegate.where_clause() {
|
||||||
remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
|
remove_useless_where_clauses(&delegate.trait_()?, &delegate.self_ty()?, wc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(delegate)
|
Some(delegate)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_impl(
|
fn transform_impl<N: ast::AstNode>(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
strukt: &ast::Struct,
|
strukt: &ast::Struct,
|
||||||
old_impl: &ast::Impl,
|
old_impl: &ast::Impl,
|
||||||
args: &Option<GenericArgList>,
|
args: &Option<GenericArgList>,
|
||||||
syntax: &syntax::SyntaxNode,
|
syntax: N,
|
||||||
) -> Option<()> {
|
) -> Option<N> {
|
||||||
let source_scope = ctx.sema.scope(old_impl.self_ty()?.syntax())?;
|
let source_scope = ctx.sema.scope(old_impl.self_ty()?.syntax())?;
|
||||||
let target_scope = ctx.sema.scope(strukt.syntax())?;
|
let target_scope = ctx.sema.scope(strukt.syntax())?;
|
||||||
let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
|
let hir_old_impl = ctx.sema.to_impl_def(old_impl)?;
|
||||||
@ -437,8 +442,7 @@ fn transform_impl(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
transform.apply(syntax);
|
N::cast(transform.apply(syntax.syntax()))
|
||||||
Some(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_instantiated_params(
|
fn remove_instantiated_params(
|
||||||
@ -570,9 +574,7 @@ where
|
|||||||
let scope = ctx.sema.scope(item.syntax())?;
|
let scope = ctx.sema.scope(item.syntax())?;
|
||||||
|
|
||||||
let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
|
let transform = PathTransform::adt_transformation(&scope, &scope, hir_adt, args.clone());
|
||||||
transform.apply(item.syntax());
|
N::cast(transform.apply(item.syntax()))
|
||||||
|
|
||||||
Some(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
|
fn has_self_type(trait_: hir::Trait, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
|
@ -743,17 +743,30 @@ fn fn_generic_params(
|
|||||||
let where_preds: Vec<ast::WherePred> =
|
let where_preds: Vec<ast::WherePred> =
|
||||||
where_preds.into_iter().map(|it| it.node.clone_for_update()).collect();
|
where_preds.into_iter().map(|it| it.node.clone_for_update()).collect();
|
||||||
|
|
||||||
|
let (generic_params, where_preds): (Vec<ast::GenericParam>, Vec<ast::WherePred>) =
|
||||||
|
if let Some(param) = generic_params.first()
|
||||||
|
&& let source_scope = ctx.sema.scope(param.syntax())?
|
||||||
|
&& let target_scope = ctx.sema.scope(&target.parent())?
|
||||||
|
&& source_scope.module() != target_scope.module()
|
||||||
|
{
|
||||||
// 4. Rewrite paths
|
// 4. Rewrite paths
|
||||||
if let Some(param) = generic_params.first() {
|
|
||||||
let source_scope = ctx.sema.scope(param.syntax())?;
|
|
||||||
let target_scope = ctx.sema.scope(&target.parent())?;
|
|
||||||
if source_scope.module() != target_scope.module() {
|
|
||||||
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
|
let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
|
||||||
let generic_params = generic_params.iter().map(|it| it.syntax());
|
let generic_params = generic_params.iter().map(|it| it.syntax());
|
||||||
let where_preds = where_preds.iter().map(|it| it.syntax());
|
let where_preds = where_preds.iter().map(|it| it.syntax());
|
||||||
transform.apply_all(generic_params.chain(where_preds));
|
transform
|
||||||
}
|
.apply_all(generic_params.chain(where_preds))
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|it| {
|
||||||
|
if let Some(it) = ast::GenericParam::cast(it.clone()) {
|
||||||
|
Some(either::Either::Left(it))
|
||||||
|
} else {
|
||||||
|
ast::WherePred::cast(it).map(either::Either::Right)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.partition_map(|it| it)
|
||||||
|
} else {
|
||||||
|
(generic_params, where_preds)
|
||||||
|
};
|
||||||
|
|
||||||
let generic_param_list = make::generic_param_list(generic_params);
|
let generic_param_list = make::generic_param_list(generic_params);
|
||||||
let where_clause =
|
let where_clause =
|
||||||
|
@ -537,8 +537,13 @@ fn inline(
|
|||||||
if let Some(generic_arg_list) = generic_arg_list.clone() {
|
if let Some(generic_arg_list) = generic_arg_list.clone() {
|
||||||
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
|
||||||
{
|
{
|
||||||
|
body.reindent_to(IndentLevel(0));
|
||||||
|
if let Some(new_body) = ast::BlockExpr::cast(
|
||||||
PathTransform::function_call(target, source, function, generic_arg_list)
|
PathTransform::function_call(target, source, function, generic_arg_list)
|
||||||
.apply(body.syntax());
|
.apply(body.syntax()),
|
||||||
|
) {
|
||||||
|
body = new_body;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ pub fn add_trait_assoc_items_to_impl(
|
|||||||
original_items
|
original_items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|InFile { file_id, value: original_item }| {
|
.map(|InFile { file_id, value: original_item }| {
|
||||||
let cloned_item = {
|
let mut cloned_item = {
|
||||||
if let Some(macro_file) = file_id.macro_file() {
|
if let Some(macro_file) = file_id.macro_file() {
|
||||||
let span_map = sema.db.expansion_span_map(macro_file);
|
let span_map = sema.db.expansion_span_map(macro_file);
|
||||||
let item_prettified = prettify_macro_expansion(
|
let item_prettified = prettify_macro_expansion(
|
||||||
@ -208,17 +208,18 @@ pub fn add_trait_assoc_items_to_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
original_item.clone_for_update()
|
original_item.clone_for_update()
|
||||||
};
|
}
|
||||||
|
.reset_indent();
|
||||||
|
|
||||||
if let Some(source_scope) = sema.scope(original_item.syntax()) {
|
if let Some(source_scope) = sema.scope(original_item.syntax()) {
|
||||||
// FIXME: Paths in nested macros are not handled well. See
|
// FIXME: Paths in nested macros are not handled well. See
|
||||||
// `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
|
// `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
|
||||||
let transform =
|
let transform =
|
||||||
PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
|
PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
|
||||||
transform.apply(cloned_item.syntax());
|
cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
|
||||||
}
|
}
|
||||||
cloned_item.remove_attrs_and_docs();
|
cloned_item.remove_attrs_and_docs();
|
||||||
cloned_item.reset_indent()
|
cloned_item
|
||||||
})
|
})
|
||||||
.map(|item| {
|
.map(|item| {
|
||||||
match &item {
|
match &item {
|
||||||
|
@ -276,7 +276,7 @@ fn get_transformed_assoc_item(
|
|||||||
let assoc_item = assoc_item.clone_for_update();
|
let assoc_item = assoc_item.clone_for_update();
|
||||||
// FIXME: Paths in nested macros are not handled well. See
|
// FIXME: Paths in nested macros are not handled well. See
|
||||||
// `macro_generated_assoc_item2` test.
|
// `macro_generated_assoc_item2` test.
|
||||||
transform.apply(assoc_item.syntax());
|
let assoc_item = ast::AssocItem::cast(transform.apply(assoc_item.syntax()))?;
|
||||||
assoc_item.remove_attrs_and_docs();
|
assoc_item.remove_attrs_and_docs();
|
||||||
Some(assoc_item)
|
Some(assoc_item)
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ fn get_transformed_fn(
|
|||||||
let fn_ = fn_.clone_for_update();
|
let fn_ = fn_.clone_for_update();
|
||||||
// FIXME: Paths in nested macros are not handled well. See
|
// FIXME: Paths in nested macros are not handled well. See
|
||||||
// `macro_generated_assoc_item2` test.
|
// `macro_generated_assoc_item2` test.
|
||||||
transform.apply(fn_.syntax());
|
let fn_ = ast::Fn::cast(transform.apply(fn_.syntax()))?;
|
||||||
fn_.remove_attrs_and_docs();
|
fn_.remove_attrs_and_docs();
|
||||||
match async_ {
|
match async_ {
|
||||||
AsyncSugaring::Desugar => {
|
AsyncSugaring::Desugar => {
|
||||||
|
@ -12,15 +12,16 @@ use span::Edition;
|
|||||||
use syntax::{
|
use syntax::{
|
||||||
NodeOrToken, SyntaxNode,
|
NodeOrToken, SyntaxNode,
|
||||||
ast::{self, AstNode, HasGenericArgs, make},
|
ast::{self, AstNode, HasGenericArgs, make},
|
||||||
ted,
|
syntax_editor::{self, SyntaxEditor},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
struct AstSubsts {
|
struct AstSubsts {
|
||||||
types_and_consts: Vec<TypeOrConst>,
|
types_and_consts: Vec<TypeOrConst>,
|
||||||
lifetimes: Vec<ast::LifetimeArg>,
|
lifetimes: Vec<ast::LifetimeArg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum TypeOrConst {
|
enum TypeOrConst {
|
||||||
Either(ast::TypeArg), // indistinguishable type or const param
|
Either(ast::TypeArg), // indistinguishable type or const param
|
||||||
Const(ast::ConstArg),
|
Const(ast::ConstArg),
|
||||||
@ -128,15 +129,18 @@ impl<'a> PathTransform<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply(&self, syntax: &SyntaxNode) {
|
#[must_use]
|
||||||
|
pub fn apply(&self, syntax: &SyntaxNode) -> SyntaxNode {
|
||||||
self.build_ctx().apply(syntax)
|
self.build_ctx().apply(syntax)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_all<'b>(&self, nodes: impl IntoIterator<Item = &'b SyntaxNode>) {
|
#[must_use]
|
||||||
|
pub fn apply_all<'b>(
|
||||||
|
&self,
|
||||||
|
nodes: impl IntoIterator<Item = &'b SyntaxNode>,
|
||||||
|
) -> Vec<SyntaxNode> {
|
||||||
let ctx = self.build_ctx();
|
let ctx = self.build_ctx();
|
||||||
for node in nodes {
|
nodes.into_iter().map(|node| ctx.apply(&node.clone())).collect()
|
||||||
ctx.apply(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
|
fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
|
||||||
@ -236,7 +240,7 @@ impl<'a> PathTransform<'a> {
|
|||||||
Some((k.name(db).display(db, target_edition).to_string(), v.lifetime()?))
|
Some((k.name(db).display(db, target_edition).to_string(), v.lifetime()?))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let ctx = Ctx {
|
let mut ctx = Ctx {
|
||||||
type_substs,
|
type_substs,
|
||||||
const_substs,
|
const_substs,
|
||||||
lifetime_substs,
|
lifetime_substs,
|
||||||
@ -272,42 +276,75 @@ fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx<'_> {
|
impl Ctx<'_> {
|
||||||
fn apply(&self, item: &SyntaxNode) {
|
fn apply(&self, item: &SyntaxNode) -> SyntaxNode {
|
||||||
// `transform_path` may update a node's parent and that would break the
|
// `transform_path` may update a node's parent and that would break the
|
||||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||||
// so that such operation is safe.
|
// so that such operation is safe.
|
||||||
let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
let item = self.transform_path(item).clone_subtree();
|
||||||
for path in paths {
|
let mut editor = SyntaxEditor::new(item.clone());
|
||||||
self.transform_path(path);
|
preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||||
}
|
|
||||||
|
|
||||||
preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
|
||||||
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
||||||
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
editor
|
||||||
|
.replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
editor.finish().new_root().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_default_values(&self, defaulted_params: Vec<DefaultedParam>) {
|
fn transform_default_values(&mut self, defaulted_params: Vec<DefaultedParam>) {
|
||||||
// By now the default values are simply copied from where they are declared
|
// By now the default values are simply copied from where they are declared
|
||||||
// and should be transformed. As any value is allowed to refer to previous
|
// and should be transformed. As any value is allowed to refer to previous
|
||||||
// generic (both type and const) parameters, they should be all iterated left-to-right.
|
// generic (both type and const) parameters, they should be all iterated left-to-right.
|
||||||
for param in defaulted_params {
|
for param in defaulted_params {
|
||||||
let value = match param {
|
let value = match ¶m {
|
||||||
Either::Left(k) => self.type_substs.get(&k).unwrap().syntax(),
|
Either::Left(k) => self.type_substs.get(k).unwrap().syntax(),
|
||||||
Either::Right(k) => self.const_substs.get(&k).unwrap(),
|
Either::Right(k) => self.const_substs.get(k).unwrap(),
|
||||||
};
|
};
|
||||||
// `transform_path` may update a node's parent and that would break the
|
// `transform_path` may update a node's parent and that would break the
|
||||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||||
// so that such operation is safe.
|
// so that such operation is safe.
|
||||||
let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
let new_value = self.transform_path(value);
|
||||||
for path in paths {
|
match param {
|
||||||
self.transform_path(path);
|
Either::Left(k) => {
|
||||||
|
self.type_substs.insert(k, ast::Type::cast(new_value.clone()).unwrap());
|
||||||
|
}
|
||||||
|
Either::Right(k) => {
|
||||||
|
self.const_substs.insert(k, new_value.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_path(&self, path: ast::Path) -> Option<()> {
|
fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode {
|
||||||
|
fn find_child_paths(root_path: &SyntaxNode) -> Vec<ast::Path> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for child in root_path.children() {
|
||||||
|
if let Some(child_path) = ast::Path::cast(child.clone()) {
|
||||||
|
result.push(child_path);
|
||||||
|
} else {
|
||||||
|
result.extend(find_child_paths(&child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
let root_path = path.clone_subtree();
|
||||||
|
let result = find_child_paths(&root_path);
|
||||||
|
let mut editor = SyntaxEditor::new(root_path.clone());
|
||||||
|
for sub_path in result {
|
||||||
|
let new = self.transform_path(sub_path.syntax());
|
||||||
|
editor.replace(sub_path.syntax(), new);
|
||||||
|
}
|
||||||
|
let update_sub_item = editor.finish().new_root().clone().clone_subtree();
|
||||||
|
let item = find_child_paths(&update_sub_item);
|
||||||
|
let mut editor = SyntaxEditor::new(update_sub_item);
|
||||||
|
for sub_path in item {
|
||||||
|
self.transform_path_(&mut editor, &sub_path);
|
||||||
|
}
|
||||||
|
editor.finish().new_root().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> {
|
||||||
if path.qualifier().is_some() {
|
if path.qualifier().is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -319,8 +356,7 @@ impl Ctx<'_> {
|
|||||||
// don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing
|
// don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let resolution = self.source_scope.speculative_resolve(path)?;
|
||||||
let resolution = self.source_scope.speculative_resolve(&path)?;
|
|
||||||
|
|
||||||
match resolution {
|
match resolution {
|
||||||
hir::PathResolution::TypeParam(tp) => {
|
hir::PathResolution::TypeParam(tp) => {
|
||||||
@ -360,12 +396,12 @@ impl Ctx<'_> {
|
|||||||
|
|
||||||
let segment = make::path_segment_ty(subst.clone(), trait_ref);
|
let segment = make::path_segment_ty(subst.clone(), trait_ref);
|
||||||
let qualified = make::path_from_segments(std::iter::once(segment), false);
|
let qualified = make::path_from_segments(std::iter::once(segment), false);
|
||||||
ted::replace(path.syntax(), qualified.clone_for_update().syntax());
|
editor.replace(path.syntax(), qualified.clone_for_update().syntax());
|
||||||
} else if let Some(path_ty) = ast::PathType::cast(parent) {
|
} else if let Some(path_ty) = ast::PathType::cast(parent) {
|
||||||
let old = path_ty.syntax();
|
let old = path_ty.syntax();
|
||||||
|
|
||||||
if old.parent().is_some() {
|
if old.parent().is_some() {
|
||||||
ted::replace(old, subst.clone_subtree().clone_for_update().syntax());
|
editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
|
||||||
} else {
|
} else {
|
||||||
// Some `path_ty` has no parent, especially ones made for default value
|
// Some `path_ty` has no parent, especially ones made for default value
|
||||||
// of type parameters.
|
// of type parameters.
|
||||||
@ -377,13 +413,13 @@ impl Ctx<'_> {
|
|||||||
}
|
}
|
||||||
let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
|
let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
|
||||||
let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
|
let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
|
||||||
ted::replace_all(
|
editor.replace_all(
|
||||||
start..=end,
|
start..=end,
|
||||||
new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
|
new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ted::replace(
|
editor.replace(
|
||||||
path.syntax(),
|
path.syntax(),
|
||||||
subst.clone_subtree().clone_for_update().syntax(),
|
subst.clone_subtree().clone_for_update().syntax(),
|
||||||
);
|
);
|
||||||
@ -409,17 +445,28 @@ impl Ctx<'_> {
|
|||||||
};
|
};
|
||||||
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
|
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
|
||||||
let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
|
let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
|
||||||
|
let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
|
||||||
if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
|
if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
|
||||||
if let Some(segment) = res.segment() {
|
if let Some(segment) = res.segment() {
|
||||||
let old = segment.get_or_create_generic_arg_list();
|
if let Some(old) = segment.generic_arg_list() {
|
||||||
ted::replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
|
res_editor.replace(
|
||||||
|
old.syntax(),
|
||||||
|
args.clone_subtree().syntax().clone_for_update(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
res_editor.insert(
|
||||||
|
syntax_editor::Position::last_child_of(segment.syntax()),
|
||||||
|
args.clone_subtree().syntax().clone_for_update(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ted::replace(path.syntax(), res.syntax())
|
}
|
||||||
|
let res = res_editor.finish().new_root().clone();
|
||||||
|
editor.replace(path.syntax().clone(), res);
|
||||||
}
|
}
|
||||||
hir::PathResolution::ConstParam(cp) => {
|
hir::PathResolution::ConstParam(cp) => {
|
||||||
if let Some(subst) = self.const_substs.get(&cp) {
|
if let Some(subst) = self.const_substs.get(&cp) {
|
||||||
ted::replace(path.syntax(), subst.clone_subtree().clone_for_update());
|
editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::PathResolution::SelfType(imp) => {
|
hir::PathResolution::SelfType(imp) => {
|
||||||
@ -456,13 +503,13 @@ impl Ctx<'_> {
|
|||||||
mod_path_to_ast(&found_path, self.target_edition).qualifier()
|
mod_path_to_ast(&found_path, self.target_edition).qualifier()
|
||||||
{
|
{
|
||||||
let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
|
let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
|
||||||
ted::replace(path.syntax(), res.syntax());
|
editor.replace(path.syntax(), res.syntax());
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ted::replace(path.syntax(), ast_ty.syntax());
|
editor.replace(path.syntax(), ast_ty.syntax());
|
||||||
}
|
}
|
||||||
hir::PathResolution::Local(_)
|
hir::PathResolution::Local(_)
|
||||||
| hir::PathResolution::Def(_)
|
| hir::PathResolution::Def(_)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user