Support generic function in generate_function assist

This commit is contained in:
Ryo Yoshida 2023-01-31 19:49:18 +09:00
parent 32955c30cd
commit 3edde6fcc1
No known key found for this signature in database
GPG key ID: E25698A930586171
5 changed files with 888 additions and 45 deletions

View file

@ -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)]

View file

@ -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

View file

@ -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.

View file

@ -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}",
)) ))
} }