Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/utils.rs')
-rw-r--r--crates/ide-assists/src/utils.rs173
1 files changed, 31 insertions, 142 deletions
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index bf1062d207..096f6678a5 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -21,8 +21,7 @@ use syntax::{
SyntaxNode, SyntaxToken, T, TextRange, TextSize, WalkEvent,
ast::{
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
- edit::{AstNodeEdit, IndentLevel},
- edit_in_place::AttrsOwnerEdit,
+ edit::{AstNodeEdit, AttrsOwnerEdit, IndentLevel},
make,
prec::ExprPrecedence,
syntax_factory::SyntaxFactory,
@@ -183,7 +182,11 @@ pub fn filter_assoc_items(
(default_methods, def.body()),
(DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
),
- _ => default_methods == DefaultMethods::No,
+ ast::AssocItem::TypeAlias(def) => matches!(
+ (default_methods, def.ty()),
+ (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
+ ),
+ ast::AssocItem::MacroCall(_) => unreachable!(),
})
.collect();
@@ -222,7 +225,7 @@ pub fn add_trait_assoc_items_to_impl(
let item_prettified = prettify_macro_expansion(
sema.db,
original_item.syntax().clone(),
- &span_map,
+ span_map,
target_scope.krate().into(),
);
if let Some(formatted) = ast::AssocItem::cast(item_prettified) {
@@ -242,8 +245,9 @@ pub fn add_trait_assoc_items_to_impl(
PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
}
- cloned_item.remove_attrs_and_docs();
- cloned_item
+ let (editor, cloned_item) = SyntaxEditor::with_ast_node(&cloned_item);
+ cloned_item.remove_attrs_and_docs(&editor);
+ ast::AssocItem::cast(editor.finish().new_root().clone()).unwrap()
})
.filter_map(|item| match item {
ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
@@ -382,18 +386,21 @@ pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
pat_head == var_head
}
-pub(crate) fn does_pat_variant_nested_or_literal(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
+pub(crate) fn does_pat_variant_nested_or_literal(
+ ctx: &AssistContext<'_, '_>,
+ pat: &ast::Pat,
+) -> bool {
check_pat_variant_nested_or_literal_with_depth(ctx, pat, 0)
}
-fn check_pat_variant_from_enum(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
+fn check_pat_variant_from_enum(ctx: &AssistContext<'_, '_>, pat: &ast::Pat) -> bool {
ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo<'_>| {
ty.adjusted().as_adt().is_some_and(|adt| matches!(adt, hir::Adt::Enum(_)))
})
}
fn check_pat_variant_nested_or_literal_with_depth(
- ctx: &AssistContext<'_>,
+ ctx: &AssistContext<'_, '_>,
pat: &ast::Pat,
depth_after_refutable: usize,
) -> bool {
@@ -409,6 +416,7 @@ fn check_pat_variant_nested_or_literal_with_depth(
| ast::Pat::MacroPat(_)
| ast::Pat::PathPat(_)
| ast::Pat::BoxPat(_)
+ | ast::Pat::DerefPat(_)
| ast::Pat::ConstBlockPat(_) => true,
ast::Pat::IdentPat(ident_pat) => ident_pat.pat().is_some_and(|pat| {
@@ -480,7 +488,7 @@ pub(crate) fn expr_fill_default(config: &AssistConfig) -> ast::Expr {
/// - `Some(None)`: no impl exists.
/// - `Some(Some(_))`: an impl exists, with no matching function names.
pub(crate) fn find_struct_impl(
- ctx: &AssistContext<'_>,
+ ctx: &AssistContext<'_, '_>,
adt: &ast::Adt,
names: &[String],
) -> Option<Option<ast::Impl>> {
@@ -536,15 +544,11 @@ pub(crate) fn generate_impl_with_item(
adt: &ast::Adt,
body: Option<ast::AssocItemList>,
) -> ast::Impl {
- generate_impl_inner_with_factory(make, false, adt, None, true, body)
+ generate_impl_inner(make, false, adt, None, true, body)
}
-pub(crate) fn generate_impl_with_factory(make: &SyntaxFactory, adt: &ast::Adt) -> ast::Impl {
- generate_impl_inner_with_factory(make, false, adt, None, true, None)
-}
-
-pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
- generate_impl_inner(false, adt, None, true, None)
+pub(crate) fn generate_impl(make: &SyntaxFactory, adt: &ast::Adt) -> ast::Impl {
+ generate_impl_inner(make, false, adt, None, true, None)
}
/// Generates the corresponding `impl <trait> for Type {}` including type
@@ -557,7 +561,7 @@ pub(crate) fn generate_trait_impl(
adt: &ast::Adt,
trait_: ast::Type,
) -> ast::Impl {
- generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, None)
+ generate_impl_inner(make, is_unsafe, adt, Some(trait_), true, None)
}
/// Generates the corresponding `impl <trait> for Type {}` including type
@@ -569,7 +573,7 @@ pub(crate) fn generate_trait_impl_intransitive(
adt: &ast::Adt,
trait_: ast::Type,
) -> ast::Impl {
- generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, None)
+ generate_impl_inner(make, false, adt, Some(trait_), false, None)
}
pub(crate) fn generate_trait_impl_intransitive_with_item(
@@ -578,7 +582,7 @@ pub(crate) fn generate_trait_impl_intransitive_with_item(
trait_: ast::Type,
body: ast::AssocItemList,
) -> ast::Impl {
- generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, Some(body))
+ generate_impl_inner(make, false, adt, Some(trait_), false, Some(body))
}
pub(crate) fn generate_trait_impl_with_item(
@@ -588,79 +592,10 @@ pub(crate) fn generate_trait_impl_with_item(
trait_: ast::Type,
body: ast::AssocItemList,
) -> ast::Impl {
- generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, Some(body))
+ generate_impl_inner(make, is_unsafe, adt, Some(trait_), true, Some(body))
}
fn generate_impl_inner(
- is_unsafe: bool,
- adt: &ast::Adt,
- trait_: Option<ast::Type>,
- trait_is_transitive: bool,
- body: Option<ast::AssocItemList>,
-) -> ast::Impl {
- // Ensure lifetime params are before type & const params
- let generic_params = adt.generic_param_list().map(|generic_params| {
- let lifetime_params =
- generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
- let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
- let param = match param {
- ast::TypeOrConstParam::Type(param) => {
- // remove defaults since they can't be specified in impls
- let mut bounds =
- param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
- if let Some(trait_) = &trait_ {
- // Add the current trait to `bounds` if the trait is transitive,
- // meaning `impl<T> Trait for U<T>` requires `T: Trait`.
- if trait_is_transitive {
- bounds.push(make::type_bound(trait_.clone()));
- }
- };
- // `{ty_param}: {bounds}`
- let param = make::type_param(param.name()?, make::type_bound_list(bounds));
- ast::GenericParam::TypeParam(param)
- }
- ast::TypeOrConstParam::Const(param) => {
- // remove defaults since they can't be specified in impls
- let param = make::const_param(param.name()?, param.ty()?);
- ast::GenericParam::ConstParam(param)
- }
- };
- Some(param)
- });
-
- make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
- });
- let generic_args =
- generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
- let adt_assoc_bounds = trait_
- .as_ref()
- .zip(generic_params.as_ref())
- .and_then(|(trait_, params)| generic_param_associated_bounds(adt, trait_, params));
-
- let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
-
- let cfg_attrs = adt.attrs().filter(|attr| matches!(attr.meta(), Some(ast::Meta::CfgMeta(_))));
- match trait_ {
- Some(trait_) => make::impl_trait(
- cfg_attrs,
- is_unsafe,
- None,
- None,
- generic_params,
- generic_args,
- false,
- trait_,
- ty,
- adt_assoc_bounds,
- adt.where_clause(),
- body,
- ),
- None => make::impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body),
- }
- .clone_for_update()
-}
-
-fn generate_impl_inner_with_factory(
make: &SyntaxFactory,
is_unsafe: bool,
adt: &ast::Adt,
@@ -700,12 +635,11 @@ fn generate_impl_inner_with_factory(
make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
});
- let generic_args =
- generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
- let adt_assoc_bounds =
- trait_.as_ref().zip(generic_params.as_ref()).and_then(|(trait_, params)| {
- generic_param_associated_bounds_with_factory(make, adt, trait_, params)
- });
+ let generic_args = generic_params.as_ref().map(|params| params.to_generic_args(make));
+ let adt_assoc_bounds = trait_
+ .as_ref()
+ .zip(generic_params.as_ref())
+ .and_then(|(trait_, params)| generic_param_associated_bounds(make, adt, trait_, params));
let ty: ast::Type = make.ty_path(make.ident_path(&adt.name().unwrap().text())).into();
@@ -730,51 +664,6 @@ fn generate_impl_inner_with_factory(
}
fn generic_param_associated_bounds(
- adt: &ast::Adt,
- trait_: &ast::Type,
- generic_params: &ast::GenericParamList,
-) -> Option<ast::WhereClause> {
- let in_type_params = |name: &ast::NameRef| {
- generic_params
- .generic_params()
- .filter_map(|param| match param {
- ast::GenericParam::TypeParam(type_param) => type_param.name(),
- _ => None,
- })
- .any(|param| param.text() == name.text())
- };
- let adt_body = match adt {
- ast::Adt::Enum(e) => e.variant_list().map(|it| it.syntax().clone()),
- ast::Adt::Struct(s) => s.field_list().map(|it| it.syntax().clone()),
- ast::Adt::Union(u) => u.record_field_list().map(|it| it.syntax().clone()),
- };
- let mut trait_where_clause = adt_body
- .into_iter()
- .flat_map(|it| it.descendants())
- .filter_map(ast::Path::cast)
- .filter_map(|path| {
- let qualifier = path.qualifier()?.as_single_segment()?;
- let qualifier = qualifier
- .name_ref()
- .or_else(|| match qualifier.type_anchor()?.ty()? {
- ast::Type::PathType(path_type) => path_type.path()?.as_single_name_ref(),
- _ => None,
- })
- .filter(in_type_params)?;
- Some((qualifier, path.segment()?.name_ref()?))
- })
- .map(|(qualifier, assoc_name)| {
- let segments = [qualifier, assoc_name].map(make::path_segment);
- let path = make::path_from_segments(segments, false);
- let bounds = Some(make::type_bound(trait_.clone()));
- make::where_pred(either::Either::Right(make::ty_path(path)), bounds)
- })
- .unique_by(|it| it.syntax().to_string())
- .peekable();
- trait_where_clause.peek().is_some().then(|| make::where_clause(trait_where_clause))
-}
-
-fn generic_param_associated_bounds_with_factory(
make: &SyntaxFactory,
adt: &ast::Adt,
trait_: &ast::Type,
@@ -1147,7 +1036,7 @@ pub(crate) fn add_group_separators(s: &str, group_size: usize) -> String {
/// Replaces the record expression, handling field shorthands including inside macros.
pub(crate) fn replace_record_field_expr(
- ctx: &AssistContext<'_>,
+ ctx: &AssistContext<'_, '_>,
edit: &mut SourceChangeBuilder,
record_field: ast::RecordExprField,
initializer: ast::Expr,