fix: rewrite code_action generate_delegate_trait
This commit is contained in:
parent
19387d3077
commit
59aa791fe6
@ -40,8 +40,8 @@ use crate::{
|
|||||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||||
Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
|
Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
|
||||||
DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
|
DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
|
||||||
Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
|
Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Struct, ToolModule, Trait,
|
||||||
TypeAlias, TypeParam, VariantDef,
|
Type, TypeAlias, TypeParam, VariantDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum DescendPreference {
|
pub enum DescendPreference {
|
||||||
@ -229,6 +229,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||||||
pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
|
pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
|
||||||
self.imp.to_module_def(file)
|
self.imp.to_module_def(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> {
|
||||||
|
self.imp.to_def(s).map(Struct::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
|
||||||
|
self.imp.to_def(i).map(Impl::from)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> SemanticsImpl<'db> {
|
impl<'db> SemanticsImpl<'db> {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1153,7 +1153,7 @@ impl SomeTrait for B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn method_(&mut self) -> bool {
|
fn method_(&mut self) -> bool {
|
||||||
<A as SomeTrait>::method_( &mut self.a )
|
<A as SomeTrait>::method_(&mut self.a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
|
@ -58,6 +58,32 @@ const USELESS_METHODS: &[&str] = &[
|
|||||||
"into_future",
|
"into_future",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub(crate) fn for_unique_generic_name(
|
||||||
|
name: &str,
|
||||||
|
existing_params: &ast::GenericParamList,
|
||||||
|
) -> SmolStr {
|
||||||
|
let param_names = existing_params
|
||||||
|
.generic_params()
|
||||||
|
.map(|param| match param {
|
||||||
|
ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(),
|
||||||
|
p => p.to_string(),
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
let mut name = name.to_string();
|
||||||
|
let base_len = name.len();
|
||||||
|
// 4*len bytes for base, and 2 bytes for 2 digits
|
||||||
|
name.reserve(4 * base_len + 2);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
while param_names.contains(&name) {
|
||||||
|
name.truncate(base_len);
|
||||||
|
name.push_str(&count.to_string());
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
name.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
|
pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
|
||||||
let c = ty
|
let c = ty
|
||||||
.type_bound_list()
|
.type_bound_list()
|
||||||
|
@ -82,6 +82,34 @@ impl<'a> PathTransform<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn impl_transformation(
|
||||||
|
target_scope: &'a SemanticsScope<'a>,
|
||||||
|
source_scope: &'a SemanticsScope<'a>,
|
||||||
|
impl_: hir::Impl,
|
||||||
|
generic_arg_list: ast::GenericArgList,
|
||||||
|
) -> PathTransform<'a> {
|
||||||
|
PathTransform {
|
||||||
|
source_scope,
|
||||||
|
target_scope,
|
||||||
|
generic_def: Some(impl_.into()),
|
||||||
|
substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn adt_transformation(
|
||||||
|
target_scope: &'a SemanticsScope<'a>,
|
||||||
|
source_scope: &'a SemanticsScope<'a>,
|
||||||
|
adt: hir::Adt,
|
||||||
|
generic_arg_list: ast::GenericArgList,
|
||||||
|
) -> PathTransform<'a> {
|
||||||
|
PathTransform {
|
||||||
|
source_scope,
|
||||||
|
target_scope,
|
||||||
|
generic_def: Some(adt.into()),
|
||||||
|
substs: get_type_args_from_arg_list(generic_arg_list).unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generic_transformation(
|
pub fn generic_transformation(
|
||||||
target_scope: &'a SemanticsScope<'a>,
|
target_scope: &'a SemanticsScope<'a>,
|
||||||
source_scope: &'a SemanticsScope<'a>,
|
source_scope: &'a SemanticsScope<'a>,
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
SyntaxNode, SyntaxToken,
|
SyntaxNode, SyntaxToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{HasArgList, HasName};
|
use super::{GenericParam, HasArgList, HasName};
|
||||||
|
|
||||||
pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
|
pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
|
||||||
fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
|
fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
|
||||||
@ -272,6 +272,36 @@ impl ast::GenericParamList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the params corresponded to generic arg
|
||||||
|
pub fn find_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option<GenericParam> {
|
||||||
|
self.generic_params().find_map(move |param| match (¶m, &generic_arg) {
|
||||||
|
(ast::GenericParam::LifetimeParam(a), ast::GenericArg::LifetimeArg(b)) => {
|
||||||
|
(a.lifetime()?.lifetime_ident_token()?.text()
|
||||||
|
== b.lifetime()?.lifetime_ident_token()?.text())
|
||||||
|
.then_some(param)
|
||||||
|
}
|
||||||
|
(ast::GenericParam::TypeParam(a), ast::GenericArg::TypeArg(b)) => {
|
||||||
|
debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
|
||||||
|
(a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
|
||||||
|
}
|
||||||
|
(ast::GenericParam::ConstParam(a), ast::GenericArg::TypeArg(b)) => {
|
||||||
|
debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
|
||||||
|
(a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the corresponding generic arg
|
||||||
|
pub fn remove_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option<GenericParam> {
|
||||||
|
let param_to_remove = self.find_generic_arg(generic_arg);
|
||||||
|
|
||||||
|
if let Some(param) = ¶m_to_remove {
|
||||||
|
self.remove_generic_param(param.clone());
|
||||||
|
}
|
||||||
|
param_to_remove
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a matching [`ast::GenericArgList`]
|
/// Constructs a matching [`ast::GenericArgList`]
|
||||||
pub fn to_generic_args(&self) -> ast::GenericArgList {
|
pub fn to_generic_args(&self) -> ast::GenericArgList {
|
||||||
let args = self.generic_params().filter_map(|param| match param {
|
let args = self.generic_params().filter_map(|param| match param {
|
||||||
@ -300,6 +330,20 @@ impl ast::WhereClause {
|
|||||||
}
|
}
|
||||||
ted::append_child(self.syntax(), predicate.syntax());
|
ted::append_child(self.syntax(), predicate.syntax());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_predicate(&self, predicate: ast::WherePred) {
|
||||||
|
if let Some(previous) = predicate.syntax().prev_sibling() {
|
||||||
|
if let Some(next_token) = previous.next_sibling_or_token() {
|
||||||
|
ted::remove_all(next_token..=predicate.syntax().clone().into());
|
||||||
|
}
|
||||||
|
} else if let Some(next) = predicate.syntax().next_sibling() {
|
||||||
|
if let Some(next_token) = next.prev_sibling_or_token() {
|
||||||
|
ted::remove_all(predicate.syntax().clone().into()..=next_token);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ted::remove(predicate.syntax());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::TypeParam {
|
impl ast::TypeParam {
|
||||||
|
@ -207,10 +207,28 @@ fn merge_gen_params(
|
|||||||
(None, Some(bs)) => Some(bs),
|
(None, Some(bs)) => Some(bs),
|
||||||
(Some(ps), None) => Some(ps),
|
(Some(ps), None) => Some(ps),
|
||||||
(Some(ps), Some(bs)) => {
|
(Some(ps), Some(bs)) => {
|
||||||
for b in bs.generic_params() {
|
// make sure lifetime is placed before other generic params
|
||||||
ps.add_generic_param(b);
|
let generic_params = ps.generic_params().merge_by(bs.generic_params(), |_, b| {
|
||||||
}
|
!matches!(b, ast::GenericParam::LifetimeParam(_))
|
||||||
Some(ps)
|
});
|
||||||
|
Some(generic_param_list(generic_params))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_where_clause(
|
||||||
|
ps: Option<ast::WhereClause>,
|
||||||
|
bs: Option<ast::WhereClause>,
|
||||||
|
) -> Option<ast::WhereClause> {
|
||||||
|
match (ps, bs) {
|
||||||
|
(None, None) => None,
|
||||||
|
(None, Some(bs)) => Some(bs),
|
||||||
|
(Some(ps), None) => Some(ps),
|
||||||
|
(Some(ps), Some(bs)) => {
|
||||||
|
let preds = where_clause(std::iter::empty()).clone_for_update();
|
||||||
|
ps.predicates().for_each(|p| preds.add_predicate(p));
|
||||||
|
bs.predicates().for_each(|p| preds.add_predicate(p));
|
||||||
|
Some(preds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,9 +269,9 @@ pub fn impl_(
|
|||||||
pub fn impl_trait(
|
pub fn impl_trait(
|
||||||
is_unsafe: bool,
|
is_unsafe: bool,
|
||||||
trait_gen_params: Option<ast::GenericParamList>,
|
trait_gen_params: Option<ast::GenericParamList>,
|
||||||
trait_gen_args: Option<ast::GenericParamList>,
|
trait_gen_args: Option<ast::GenericArgList>,
|
||||||
type_gen_params: Option<ast::GenericParamList>,
|
type_gen_params: Option<ast::GenericParamList>,
|
||||||
type_gen_args: Option<ast::GenericParamList>,
|
type_gen_args: Option<ast::GenericArgList>,
|
||||||
is_negative: bool,
|
is_negative: bool,
|
||||||
path_type: ast::Type,
|
path_type: ast::Type,
|
||||||
ty: ast::Type,
|
ty: ast::Type,
|
||||||
@ -262,15 +280,9 @@ pub fn impl_trait(
|
|||||||
body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
|
body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
|
||||||
) -> ast::Impl {
|
) -> ast::Impl {
|
||||||
let is_unsafe = if is_unsafe { "unsafe " } else { "" };
|
let is_unsafe = if is_unsafe { "unsafe " } else { "" };
|
||||||
let ty_gen_args = match merge_gen_params(type_gen_params.clone(), type_gen_args) {
|
|
||||||
Some(pars) => pars.to_generic_args().to_string(),
|
|
||||||
None => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let tr_gen_args = match merge_gen_params(trait_gen_params.clone(), trait_gen_args) {
|
let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default();
|
||||||
Some(pars) => pars.to_generic_args().to_string(),
|
let type_gen_args = type_gen_args.map(|args| args.to_string()).unwrap_or_default();
|
||||||
None => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
|
let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
|
||||||
Some(pars) => pars.to_string(),
|
Some(pars) => pars.to_string(),
|
||||||
@ -279,25 +291,15 @@ pub fn impl_trait(
|
|||||||
|
|
||||||
let is_negative = if is_negative { "! " } else { "" };
|
let is_negative = if is_negative { "! " } else { "" };
|
||||||
|
|
||||||
let where_clause = match (ty_where_clause, trait_where_clause) {
|
let where_clause = merge_where_clause(ty_where_clause, trait_where_clause)
|
||||||
(None, None) => " ".to_string(),
|
.map_or_else(|| " ".to_string(), |wc| format!("\n{}\n", wc));
|
||||||
(None, Some(tr)) => format!("\n{}\n", tr).to_string(),
|
|
||||||
(Some(ty), None) => format!("\n{}\n", ty).to_string(),
|
|
||||||
(Some(ty), Some(tr)) => {
|
|
||||||
let updated = ty.clone_for_update();
|
|
||||||
tr.predicates().for_each(|p| {
|
|
||||||
ty.add_predicate(p);
|
|
||||||
});
|
|
||||||
format!("\n{}\n", updated).to_string()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let body = match body {
|
let body = match body {
|
||||||
Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
|
Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{tr_gen_args} for {ty}{ty_gen_args}{where_clause}{{{}}}" , body))
|
ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{{{}}}" , body))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType {
|
pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType {
|
||||||
@ -922,6 +924,10 @@ pub fn type_param(name: ast::Name, bounds: Option<ast::TypeBoundList>) -> ast::T
|
|||||||
ast_from_text(&format!("fn f<{name}{bounds}>() {{ }}"))
|
ast_from_text(&format!("fn f<{name}{bounds}>() {{ }}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn const_param(name: ast::Name, ty: ast::Type) -> ast::ConstParam {
|
||||||
|
ast_from_text(&format!("fn f<const {name}: {ty}>() {{ }}"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
|
pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
|
||||||
ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
|
ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
|
||||||
}
|
}
|
||||||
@ -948,9 +954,7 @@ pub fn turbofish_generic_arg_list(
|
|||||||
ast_from_text(&format!("const S: T::<{args}> = ();"))
|
ast_from_text(&format!("const S: T::<{args}> = ();"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generic_arg_list(
|
pub fn generic_arg_list(args: impl IntoIterator<Item = ast::GenericArg>) -> ast::GenericArgList {
|
||||||
args: impl IntoIterator<Item = ast::GenericArg>,
|
|
||||||
) -> ast::GenericArgList {
|
|
||||||
let args = args.into_iter().join(", ");
|
let args = args.into_iter().join(", ");
|
||||||
ast_from_text(&format!("const S: T<{args}> = ();"))
|
ast_from_text(&format!("const S: T<{args}> = ();"))
|
||||||
}
|
}
|
||||||
|
@ -572,6 +572,16 @@ impl ast::Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ast::Type {
|
||||||
|
pub fn generic_arg_list(&self) -> Option<ast::GenericArgList> {
|
||||||
|
if let ast::Type::PathType(path_type) = self {
|
||||||
|
path_type.path()?.segment()?.generic_arg_list()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum FieldKind {
|
pub enum FieldKind {
|
||||||
Name(ast::NameRef),
|
Name(ast::NameRef),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user