mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Support generic function in generate_function
assist
This commit is contained in:
parent
32955c30cd
commit
3edde6fcc1
5 changed files with 888 additions and 45 deletions
|
@ -2165,6 +2165,16 @@ impl AsAssocItem for ModuleDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl AsAssocItem for DefWithBody {
|
||||||
|
fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
|
||||||
|
match self {
|
||||||
|
DefWithBody::Function(it) => it.as_assoc_item(db),
|
||||||
|
DefWithBody::Const(it) => it.as_assoc_item(db),
|
||||||
|
DefWithBody::Static(_) | DefWithBody::Variant(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
|
fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
|
||||||
where
|
where
|
||||||
ID: Lookup<Data = AssocItemLoc<AST>>,
|
ID: Lookup<Data = AssocItemLoc<AST>>,
|
||||||
|
@ -2560,6 +2570,14 @@ impl GenericParam {
|
||||||
GenericParam::LifetimeParam(it) => it.name(db),
|
GenericParam::LifetimeParam(it) => it.name(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parent(self) -> GenericDef {
|
||||||
|
match self {
|
||||||
|
GenericParam::TypeParam(it) => it.id.parent().into(),
|
||||||
|
GenericParam::ConstParam(it) => it.id.parent().into(),
|
||||||
|
GenericParam::LifetimeParam(it) => it.id.parent.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
let tail_expr_finished =
|
let tail_expr_finished =
|
||||||
if is_async { make::expr_await(tail_expr) } else { tail_expr };
|
if is_async { make::expr_await(tail_expr) } else { tail_expr };
|
||||||
let body = make::block_expr([], Some(tail_expr_finished));
|
let body = make::block_expr([], Some(tail_expr_finished));
|
||||||
let f = make::fn_(vis, name, type_params, params, body, ret_type, is_async)
|
let f = make::fn_(vis, name, type_params, None, params, body, ret_type, is_async)
|
||||||
.indent(ast::edit::IndentLevel(1))
|
.indent(ast::edit::IndentLevel(1))
|
||||||
.clone_for_update();
|
.clone_for_update();
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,7 @@ use syntax::{
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct PathTransform<'a> {
|
pub struct PathTransform<'a> {
|
||||||
generic_def: hir::GenericDef,
|
generic_def: Option<hir::GenericDef>,
|
||||||
substs: Vec<ast::Type>,
|
substs: Vec<ast::Type>,
|
||||||
target_scope: &'a SemanticsScope<'a>,
|
target_scope: &'a SemanticsScope<'a>,
|
||||||
source_scope: &'a SemanticsScope<'a>,
|
source_scope: &'a SemanticsScope<'a>,
|
||||||
|
@ -49,7 +49,7 @@ impl<'a> PathTransform<'a> {
|
||||||
PathTransform {
|
PathTransform {
|
||||||
source_scope,
|
source_scope,
|
||||||
target_scope,
|
target_scope,
|
||||||
generic_def: trait_.into(),
|
generic_def: Some(trait_.into()),
|
||||||
substs: get_syntactic_substs(impl_).unwrap_or_default(),
|
substs: get_syntactic_substs(impl_).unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,28 +63,42 @@ impl<'a> PathTransform<'a> {
|
||||||
PathTransform {
|
PathTransform {
|
||||||
source_scope,
|
source_scope,
|
||||||
target_scope,
|
target_scope,
|
||||||
generic_def: function.into(),
|
generic_def: Some(function.into()),
|
||||||
substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
|
substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generic_transformation(
|
||||||
|
target_scope: &'a SemanticsScope<'a>,
|
||||||
|
source_scope: &'a SemanticsScope<'a>,
|
||||||
|
) -> PathTransform<'a> {
|
||||||
|
PathTransform { source_scope, target_scope, generic_def: None, substs: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply(&self, syntax: &SyntaxNode) {
|
pub fn apply(&self, syntax: &SyntaxNode) {
|
||||||
self.build_ctx().apply(syntax)
|
self.build_ctx().apply(syntax)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_all<'b>(&self, nodes: impl IntoIterator<Item = &'b SyntaxNode>) {
|
||||||
|
let ctx = self.build_ctx();
|
||||||
|
for node in nodes {
|
||||||
|
ctx.apply(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_ctx(&self) -> Ctx<'a> {
|
fn build_ctx(&self) -> Ctx<'a> {
|
||||||
let db = self.source_scope.db;
|
let db = self.source_scope.db;
|
||||||
let target_module = self.target_scope.module();
|
let target_module = self.target_scope.module();
|
||||||
let source_module = self.source_scope.module();
|
let source_module = self.source_scope.module();
|
||||||
let skip = match self.generic_def {
|
let skip = match self.generic_def {
|
||||||
// this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
|
// this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
|
||||||
hir::GenericDef::Trait(_) => 1,
|
Some(hir::GenericDef::Trait(_)) => 1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
let substs_by_param: FxHashMap<_, _> = self
|
let substs_by_param: FxHashMap<_, _> = self
|
||||||
.generic_def
|
.generic_def
|
||||||
.type_params(db)
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.flat_map(|it| it.type_params(db))
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
// The actual list of trait type parameters may be longer than the one
|
// The actual list of trait type parameters may be longer than the one
|
||||||
// used in the `impl` block due to trailing default type parameters.
|
// used in the `impl` block due to trailing default type parameters.
|
||||||
|
|
|
@ -823,6 +823,7 @@ pub fn fn_(
|
||||||
visibility: Option<ast::Visibility>,
|
visibility: Option<ast::Visibility>,
|
||||||
fn_name: ast::Name,
|
fn_name: ast::Name,
|
||||||
type_params: Option<ast::GenericParamList>,
|
type_params: Option<ast::GenericParamList>,
|
||||||
|
where_clause: Option<ast::WhereClause>,
|
||||||
params: ast::ParamList,
|
params: ast::ParamList,
|
||||||
body: ast::BlockExpr,
|
body: ast::BlockExpr,
|
||||||
ret_type: Option<ast::RetType>,
|
ret_type: Option<ast::RetType>,
|
||||||
|
@ -832,6 +833,10 @@ pub fn fn_(
|
||||||
Some(type_params) => format!("{type_params}"),
|
Some(type_params) => format!("{type_params}"),
|
||||||
None => "".into(),
|
None => "".into(),
|
||||||
};
|
};
|
||||||
|
let where_clause = match where_clause {
|
||||||
|
Some(it) => format!("{it} "),
|
||||||
|
None => "".into(),
|
||||||
|
};
|
||||||
let ret_type = match ret_type {
|
let ret_type = match ret_type {
|
||||||
Some(ret_type) => format!("{ret_type} "),
|
Some(ret_type) => format!("{ret_type} "),
|
||||||
None => "".into(),
|
None => "".into(),
|
||||||
|
@ -844,7 +849,7 @@ pub fn fn_(
|
||||||
let async_literal = if is_async { "async " } else { "" };
|
let async_literal = if is_async { "async " } else { "" };
|
||||||
|
|
||||||
ast_from_text(&format!(
|
ast_from_text(&format!(
|
||||||
"{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}",
|
"{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue