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.rs | 173 |
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, |