Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_methods.rs45
-rw-r--r--crates/ide-db/src/path_transform.rs21
2 files changed, 41 insertions, 25 deletions
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index dc02aaf9af..1f5c24f8ea 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -107,31 +107,48 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|edit| {
// Create the function
let method_source = match ctx.sema.source(method) {
- Some(source) => source.value,
+ Some(source) => {
+ let v = source.value.clone_for_update();
+ let source_scope = ctx.sema.scope(v.syntax());
+ let target_scope = ctx.sema.scope(strukt.syntax());
+ if let (Some(s), Some(t)) = (source_scope, target_scope) {
+ PathTransform::generic_transformation(&t, &s).apply(v.syntax());
+ }
+ v
+ }
None => return,
};
+
let vis = method_source.visibility();
+ let is_async = method_source.async_token().is_some();
+ let is_const = method_source.const_token().is_some();
+ let is_unsafe = method_source.unsafe_token().is_some();
+
let fn_name = make::name(&name);
+
+ let type_params = method_source.generic_param_list();
+ let where_clause = method_source.where_clause();
let params =
method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
- let type_params = method_source.generic_param_list();
- let arg_list = match method_source.param_list() {
- Some(list) => convert_param_list_to_arg_list(list),
- None => make::arg_list([]),
- };
+
+ // compute the `body`
+ let arg_list = method_source
+ .param_list()
+ .map(|list| convert_param_list_to_arg_list(list))
+ .unwrap_or_else(|| make::arg_list([]));
+
let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list);
- let ret_type = method_source.ret_type();
- let is_async = method_source.async_token().is_some();
- let is_const = method_source.const_token().is_some();
- let is_unsafe = method_source.unsafe_token().is_some();
let tail_expr_finished =
if is_async { make::expr_await(tail_expr) } else { tail_expr };
let body = make::block_expr([], Some(tail_expr_finished));
+
+ let ret_type = method_source.ret_type();
+
let f = make::fn_(
vis,
fn_name,
type_params,
- method_source.where_clause(),
+ where_clause,
params,
body,
ret_type,
@@ -184,12 +201,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
let assoc_items = impl_def.get_or_create_assoc_item_list();
assoc_items.add_item(f.clone().into());
- if let Some((target, source)) =
- ctx.sema.scope(strukt.syntax()).zip(ctx.sema.scope(method_source.syntax()))
- {
- PathTransform::generic_transformation(&target, &source).apply(f.syntax());
- }
-
if let Some(cap) = ctx.config.snippet_cap {
edit.add_tabstop_before(cap, f)
}
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index edfeddc1bc..47bcaae259 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -3,6 +3,7 @@
use crate::helpers::mod_path_to_ast;
use either::Either;
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
+use itertools::Itertools;
use rustc_hash::FxHashMap;
use syntax::{
ast::{self, make, AstNode},
@@ -227,11 +228,15 @@ struct Ctx<'a> {
same_self_type: bool,
}
-fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
- item.preorder().filter_map(|event| match event {
- syntax::WalkEvent::Enter(_) => None,
- syntax::WalkEvent::Leave(node) => Some(node),
- })
+fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
+ let x = item
+ .preorder()
+ .filter_map(|event| match event {
+ syntax::WalkEvent::Enter(node) => Some(node),
+ syntax::WalkEvent::Leave(_) => None,
+ })
+ .collect_vec();
+ x.into_iter().rev()
}
impl Ctx<'_> {
@@ -239,12 +244,12 @@ impl Ctx<'_> {
// `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
// so that such operation is safe.
- let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
+ let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}
- postorder(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()) {
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
}
@@ -263,7 +268,7 @@ impl Ctx<'_> {
// `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
// so that such operation is safe.
- let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
+ let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}