From 4d2e25a034385f57f2cfc6b4f4e725f827cff923 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 9 Aug 2021 21:47:44 +0200 Subject: [PATCH 1/3] move trait body gen code to utils --- .../replace_derive_with_manual_impl.rs | 151 +----------------- crates/ide_assists/src/utils.rs | 3 + .../ide_assists/src/utils/gen_trait_body.rs | 149 +++++++++++++++++ 3 files changed, 154 insertions(+), 149 deletions(-) create mode 100644 crates/ide_assists/src/utils/gen_trait_body.rs diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index bcabca64b32..a52592581b1 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs @@ -2,13 +2,12 @@ use hir::ModuleDef; use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast}; use ide_db::items_locator; use itertools::Itertools; -use syntax::ast::edit::AstNodeEdit; -use syntax::ted; use syntax::{ ast::{self, make, AstNode, NameOwner}, SyntaxKind::{IDENT, WHITESPACE}, }; +use crate::utils::gen_trait_body; use crate::{ assist_context::{AssistBuilder, AssistContext, Assists}, utils::{ @@ -169,158 +168,12 @@ fn impl_def_from_trait( // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { - let _ = gen_trait_body_impl(func, trait_path, adt, annotated_name); + let _ = gen_trait_body(func, trait_path, adt, annotated_name); }; Some((impl_def, first_assoc_item)) } -/// Generate custom trait bodies where possible. -/// -/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning -/// `None` means that generating a custom trait body failed, and the body will remain -/// as `todo!` instead. -fn gen_trait_body_impl( - func: &ast::Fn, - trait_path: &ast::Path, - adt: &ast::Adt, - annotated_name: &ast::Name, -) -> Option<()> { - match trait_path.segment()?.name_ref()?.text().as_str() { - "Debug" => gen_debug_impl(adt, func, annotated_name), - "Default" => gen_default_impl(adt, func), - _ => None, - } -} - -/// Generate a `Debug` impl based on the fields and members of the target type. -fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn, annotated_name: &ast::Name) -> Option<()> { - match adt { - // `Debug` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => None, - - // => match self { Self::Variant => write!(f, "Variant") } - ast::Adt::Enum(enum_) => { - let list = enum_.variant_list()?; - let mut arms = vec![]; - for variant in list.variants() { - let name = variant.name()?; - let left = make::ext::ident_path("Self"); - let right = make::ext::ident_path(&format!("{}", name)); - let variant_name = make::path_pat(make::path_concat(left, right)); - - let target = make::expr_path(make::ext::ident_path("f").into()); - let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); - let args = make::arg_list(vec![target, fmt_string]); - let macro_name = make::expr_path(make::ext::ident_path("write")); - let macro_call = make::expr_macro_call(macro_name, args); - - arms.push(make::match_arm(Some(variant_name.into()), None, macro_call.into())); - } - - let match_target = make::expr_path(make::ext::ident_path("self")); - let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - let match_expr = make::expr_match(match_target, list); - - let body = make::block_expr(None, Some(match_expr)); - let body = body.indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - - ast::Adt::Struct(strukt) => { - let name = format!("\"{}\"", annotated_name); - let args = make::arg_list(Some(make::expr_literal(&name).into())); - let target = make::expr_path(make::ext::ident_path("f")); - - let expr = match strukt.field_list() { - // => f.debug_struct("Name").finish() - None => make::expr_method_call(target, make::name_ref("debug_struct"), args), - - // => f.debug_struct("Name").field("foo", &self.foo).finish() - Some(ast::FieldList::RecordFieldList(field_list)) => { - let method = make::name_ref("debug_struct"); - let mut expr = make::expr_method_call(target, method, args); - for field in field_list.fields() { - let name = field.name()?; - let f_name = make::expr_literal(&(format!("\"{}\"", name))).into(); - let f_path = make::expr_path(make::ext::ident_path("self")); - let f_path = make::expr_ref(f_path, false); - let f_path = make::expr_field(f_path, &format!("{}", name)).into(); - let args = make::arg_list(vec![f_name, f_path]); - expr = make::expr_method_call(expr, make::name_ref("field"), args); - } - expr - } - - // => f.debug_tuple("Name").field(self.0).finish() - Some(ast::FieldList::TupleFieldList(field_list)) => { - let method = make::name_ref("debug_tuple"); - let mut expr = make::expr_method_call(target, method, args); - for (idx, _) in field_list.fields().enumerate() { - let f_path = make::expr_path(make::ext::ident_path("self")); - let f_path = make::expr_ref(f_path, false); - let f_path = make::expr_field(f_path, &format!("{}", idx)).into(); - let method = make::name_ref("field"); - expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path))); - } - expr - } - }; - - let method = make::name_ref("finish"); - let expr = make::expr_method_call(expr, method, make::arg_list(None)); - let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - } -} - -/// Generate a `Debug` impl based on the fields and members of the target type. -fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - fn gen_default_call() -> ast::Expr { - let trait_name = make::ext::ident_path("Default"); - let method_name = make::ext::ident_path("default"); - let fn_name = make::expr_path(make::path_concat(trait_name, method_name)); - make::expr_call(fn_name, make::arg_list(None)) - } - match adt { - // `Debug` cannot be derived for unions, so no default impl can be provided. - ast::Adt::Union(_) => None, - // Deriving `Debug` for enums is not stable yet. - ast::Adt::Enum(_) => None, - ast::Adt::Struct(strukt) => { - let expr = match strukt.field_list() { - Some(ast::FieldList::RecordFieldList(field_list)) => { - let mut fields = vec![]; - for field in field_list.fields() { - let method_call = gen_default_call(); - let name_ref = make::name_ref(&field.name()?.to_string()); - let field = make::record_expr_field(name_ref, Some(method_call)); - fields.push(field); - } - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(fields); - make::record_expr(struct_name, fields).into() - } - Some(ast::FieldList::TupleFieldList(field_list)) => { - let struct_name = make::expr_path(make::ext::ident_path("Self")); - let fields = field_list.fields().map(|_| gen_default_call()); - make::expr_call(struct_name, make::arg_list(fields)) - } - None => { - let struct_name = make::ext::ident_path("Self"); - let fields = make::record_expr_field_list(None); - make::record_expr(struct_name, fields).into() - } - }; - let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); - ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); - Some(()) - } - } -} fn update_attribute( builder: &mut AssistBuilder, input: &ast::TokenTree, diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index bcd7501724f..6552c1feb96 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs @@ -1,6 +1,7 @@ //! Assorted functions shared by several assists. pub(crate) mod suggest_name; +mod gen_trait_body; use std::ops; @@ -25,6 +26,8 @@ use syntax::{ use crate::assist_context::{AssistBuilder, AssistContext}; +pub(crate) use gen_trait_body::gen_trait_body; + pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { extract_trivial_expression(&block) .filter(|expr| !expr.syntax().text().contains_char('\n')) diff --git a/crates/ide_assists/src/utils/gen_trait_body.rs b/crates/ide_assists/src/utils/gen_trait_body.rs new file mode 100644 index 00000000000..996cbc842e9 --- /dev/null +++ b/crates/ide_assists/src/utils/gen_trait_body.rs @@ -0,0 +1,149 @@ +use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner}; +use syntax::ted; + +/// Generate custom trait bodies where possible. +/// +/// Returns `Option` so that we can use `?` rather than `if let Some`. Returning +/// `None` means that generating a custom trait body failed, and the body will remain +/// as `todo!` instead. +pub(crate) fn gen_trait_body( + func: &ast::Fn, + trait_path: &ast::Path, + adt: &ast::Adt, + annotated_name: &ast::Name, +) -> Option<()> { + match trait_path.segment()?.name_ref()?.text().as_str() { + "Debug" => gen_debug_impl(adt, func, annotated_name), + "Default" => gen_default_impl(adt, func), + _ => None, + } +} + +/// Generate a `Debug` impl based on the fields and members of the target type. +fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn, annotated_name: &ast::Name) -> Option<()> { + match adt { + // `Debug` cannot be derived for unions, so no default impl can be provided. + ast::Adt::Union(_) => None, + + // => match self { Self::Variant => write!(f, "Variant") } + ast::Adt::Enum(enum_) => { + let list = enum_.variant_list()?; + let mut arms = vec![]; + for variant in list.variants() { + let name = variant.name()?; + let left = make::ext::ident_path("Self"); + let right = make::ext::ident_path(&format!("{}", name)); + let variant_name = make::path_pat(make::path_concat(left, right)); + + let target = make::expr_path(make::ext::ident_path("f").into()); + let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); + let args = make::arg_list(vec![target, fmt_string]); + let macro_name = make::expr_path(make::ext::ident_path("write")); + let macro_call = make::expr_macro_call(macro_name, args); + + arms.push(make::match_arm(Some(variant_name.into()), None, macro_call.into())); + } + + let match_target = make::expr_path(make::ext::ident_path("self")); + let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); + let match_expr = make::expr_match(match_target, list); + + let body = make::block_expr(None, Some(match_expr)); + let body = body.indent(ast::edit::IndentLevel(1)); + ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); + Some(()) + } + + ast::Adt::Struct(strukt) => { + let name = format!("\"{}\"", annotated_name); + let args = make::arg_list(Some(make::expr_literal(&name).into())); + let target = make::expr_path(make::ext::ident_path("f")); + + let expr = match strukt.field_list() { + // => f.debug_struct("Name").finish() + None => make::expr_method_call(target, make::name_ref("debug_struct"), args), + + // => f.debug_struct("Name").field("foo", &self.foo).finish() + Some(ast::FieldList::RecordFieldList(field_list)) => { + let method = make::name_ref("debug_struct"); + let mut expr = make::expr_method_call(target, method, args); + for field in field_list.fields() { + let name = field.name()?; + let f_name = make::expr_literal(&(format!("\"{}\"", name))).into(); + let f_path = make::expr_path(make::ext::ident_path("self")); + let f_path = make::expr_ref(f_path, false); + let f_path = make::expr_field(f_path, &format!("{}", name)).into(); + let args = make::arg_list(vec![f_name, f_path]); + expr = make::expr_method_call(expr, make::name_ref("field"), args); + } + expr + } + + // => f.debug_tuple("Name").field(self.0).finish() + Some(ast::FieldList::TupleFieldList(field_list)) => { + let method = make::name_ref("debug_tuple"); + let mut expr = make::expr_method_call(target, method, args); + for (idx, _) in field_list.fields().enumerate() { + let f_path = make::expr_path(make::ext::ident_path("self")); + let f_path = make::expr_ref(f_path, false); + let f_path = make::expr_field(f_path, &format!("{}", idx)).into(); + let method = make::name_ref("field"); + expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path))); + } + expr + } + }; + + let method = make::name_ref("finish"); + let expr = make::expr_method_call(expr, method, make::arg_list(None)); + let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); + ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); + Some(()) + } + } +} + +/// Generate a `Debug` impl based on the fields and members of the target type. +fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { + fn gen_default_call() -> ast::Expr { + let trait_name = make::ext::ident_path("Default"); + let method_name = make::ext::ident_path("default"); + let fn_name = make::expr_path(make::path_concat(trait_name, method_name)); + make::expr_call(fn_name, make::arg_list(None)) + } + match adt { + // `Debug` cannot be derived for unions, so no default impl can be provided. + ast::Adt::Union(_) => None, + // Deriving `Debug` for enums is not stable yet. + ast::Adt::Enum(_) => None, + ast::Adt::Struct(strukt) => { + let expr = match strukt.field_list() { + Some(ast::FieldList::RecordFieldList(field_list)) => { + let mut fields = vec![]; + for field in field_list.fields() { + let method_call = gen_default_call(); + let name_ref = make::name_ref(&field.name()?.to_string()); + let field = make::record_expr_field(name_ref, Some(method_call)); + fields.push(field); + } + let struct_name = make::ext::ident_path("Self"); + let fields = make::record_expr_field_list(fields); + make::record_expr(struct_name, fields).into() + } + Some(ast::FieldList::TupleFieldList(field_list)) => { + let struct_name = make::expr_path(make::ext::ident_path("Self")); + let fields = field_list.fields().map(|_| gen_default_call()); + make::expr_call(struct_name, make::arg_list(fields)) + } + None => { + let struct_name = make::ext::ident_path("Self"); + let fields = make::record_expr_field_list(None); + make::record_expr(struct_name, fields).into() + } + }; + let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)); + ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); + Some(()) + } + } +} From d6b788a9eec347d47aa5b77cd617532e438867f9 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 9 Aug 2021 23:26:28 +0200 Subject: [PATCH 2/3] Add trait codegen to `add_missing_impl_members` assist --- crates/hir/src/has_source.rs | 14 ++++- .../src/handlers/add_missing_impl_members.rs | 62 ++++++++++++++++--- .../replace_derive_with_manual_impl.rs | 2 +- .../ide_assists/src/utils/gen_trait_body.rs | 14 ++--- crates/rust-analyzer/tests/slow-tests/tidy.rs | 1 + 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 197149c5ebb..3a014545138 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -10,8 +10,8 @@ use hir_expand::InFile; use syntax::ast; use crate::{ - db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam, - MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, + db::HirDatabase, Adt, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, + LifetimeParam, MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, }; pub trait HasSource { @@ -56,6 +56,16 @@ impl HasSource for Field { Some(field_source) } } +impl HasSource for Adt { + type Ast = ast::Adt; + fn source(self, db: &dyn HirDatabase) -> Option> { + match self { + Adt::Struct(s) => Some(s.source(db)?.map(|s| ast::Adt::Struct(s))), + Adt::Union(u) => Some(u.source(db)?.map(|u| ast::Adt::Union(u))), + Adt::Enum(e) => Some(e.source(db)?.map(|e| ast::Adt::Enum(e))), + } + } +} impl HasSource for Struct { type Ast = ast::Struct; fn source(self, db: &dyn HirDatabase) -> Option> { diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs index 59d5f48301b..87c8f5e5482 100644 --- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs @@ -1,10 +1,12 @@ +use hir::HasSource; use ide_db::traits::resolve_target_trait; -use syntax::ast::{self, AstNode}; +use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, + add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_body, render_snippet, Cursor, + DefaultMethods, }, AssistId, AssistKind, }; @@ -115,18 +117,26 @@ fn add_missing_impl_members_inner( let target = impl_def.syntax().text_range(); acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { let target_scope = ctx.sema.scope(impl_def.syntax()); - let (new_impl_def, first_new_item) = - add_trait_assoc_items_to_impl(&ctx.sema, missing_items, trait_, impl_def, target_scope); + let (new_impl_def, first_new_item) = add_trait_assoc_items_to_impl( + &ctx.sema, + missing_items, + trait_, + impl_def.clone(), + target_scope, + ); match ctx.config.snippet_cap { None => builder.replace(target, new_impl_def.to_string()), Some(cap) => { let mut cursor = Cursor::Before(first_new_item.syntax()); let placeholder; if let ast::AssocItem::Fn(func) = &first_new_item { - if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { - if m.syntax().text() == "todo!()" { - placeholder = m; - cursor = Cursor::Replace(placeholder.syntax()); + if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() { + if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) + { + if m.syntax().text() == "todo!()" { + placeholder = m; + cursor = Cursor::Replace(placeholder.syntax()); + } } } } @@ -140,6 +150,18 @@ fn add_missing_impl_members_inner( }) } +fn try_gen_trait_body( + ctx: &AssistContext, + func: &ast::Fn, + trait_: &hir::Trait, + impl_def: &ast::Impl, +) -> Option<()> { + let trait_path = make::path_from_text(&trait_.name(ctx.db()).to_string()); + let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; + let adt = hir_ty.as_adt()?.source(ctx.db())?; + gen_trait_body(func, &trait_path, &adt.value) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -847,4 +869,28 @@ impl T for () { ", ); } + + #[test] + fn test_default_body_generation() { + check_assist( + add_missing_impl_members, + r#" +//- minicore: default +struct Foo(usize); + +impl Default for Foo { + $0 +} +"#, + r#" +struct Foo(usize); + +impl Default for Foo { + $0fn default() -> Self { + Self(Default::default()) + } +} +"#, + ) + } } diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index a52592581b1..77a6e154627 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs @@ -168,7 +168,7 @@ fn impl_def_from_trait( // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { - let _ = gen_trait_body(func, trait_path, adt, annotated_name); + let _ = gen_trait_body(func, trait_path, adt); }; Some((impl_def, first_assoc_item)) diff --git a/crates/ide_assists/src/utils/gen_trait_body.rs b/crates/ide_assists/src/utils/gen_trait_body.rs index 996cbc842e9..e8d11f42b0e 100644 --- a/crates/ide_assists/src/utils/gen_trait_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_body.rs @@ -1,3 +1,5 @@ +//! This module contains functions to generate default trait impl function bodies where possible. + use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner}; use syntax::ted; @@ -6,21 +8,17 @@ use syntax::ted; /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning /// `None` means that generating a custom trait body failed, and the body will remain /// as `todo!` instead. -pub(crate) fn gen_trait_body( - func: &ast::Fn, - trait_path: &ast::Path, - adt: &ast::Adt, - annotated_name: &ast::Name, -) -> Option<()> { +pub(crate) fn gen_trait_body(func: &ast::Fn, trait_path: &ast::Path, adt: &ast::Adt) -> Option<()> { match trait_path.segment()?.name_ref()?.text().as_str() { - "Debug" => gen_debug_impl(adt, func, annotated_name), + "Debug" => gen_debug_impl(adt, func), "Default" => gen_default_impl(adt, func), _ => None, } } /// Generate a `Debug` impl based on the fields and members of the target type. -fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn, annotated_name: &ast::Name) -> Option<()> { +fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { + let annotated_name = adt.name()?; match adt { // `Debug` cannot be derived for unions, so no default impl can be provided. ast::Adt::Union(_) => None, diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 4c3ff31533f..c895e48f3df 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -280,6 +280,7 @@ fn check_todo(path: &Path, text: &str) { "ast/make.rs", // The documentation in string literals may contain anything for its own purposes "ide_db/src/helpers/generated_lints.rs", + "ide_assists/src/utils/gen_trait_body.rs", "ide_assists/src/tests/generated.rs", ]; if need_todo.iter().any(|p| path.ends_with(p)) { From 326890753cd146d09d45a330016624c020abdd9e Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Tue, 10 Aug 2021 12:21:48 +0200 Subject: [PATCH 3/3] implement feedback from review --- .../src/handlers/add_missing_impl_members.rs | 8 ++++---- .../src/handlers/replace_derive_with_manual_impl.rs | 7 +++---- crates/ide_assists/src/utils.rs | 4 ++-- .../{gen_trait_body.rs => gen_trait_fn_body.rs} | 12 +++++++++--- crates/rust-analyzer/tests/slow-tests/tidy.rs | 2 +- 5 files changed, 19 insertions(+), 14 deletions(-) rename crates/ide_assists/src/utils/{gen_trait_body.rs => gen_trait_fn_body.rs} (97%) diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs index 87c8f5e5482..a145598c791 100644 --- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs @@ -5,8 +5,8 @@ use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_body, render_snippet, Cursor, - DefaultMethods, + add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, render_snippet, + Cursor, DefaultMethods, }, AssistId, AssistKind, }; @@ -156,10 +156,10 @@ fn try_gen_trait_body( trait_: &hir::Trait, impl_def: &ast::Impl, ) -> Option<()> { - let trait_path = make::path_from_text(&trait_.name(ctx.db()).to_string()); + let trait_path = make::ext::ident_path(&trait_.name(ctx.db()).to_string()); let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; let adt = hir_ty.as_adt()?.source(ctx.db())?; - gen_trait_body(func, &trait_path, &adt.value) + gen_trait_fn_body(func, &trait_path, &adt.value) } #[cfg(test)] diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index 77a6e154627..2add705db2e 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs @@ -7,12 +7,11 @@ use syntax::{ SyntaxKind::{IDENT, WHITESPACE}, }; -use crate::utils::gen_trait_body; use crate::{ assist_context::{AssistBuilder, AssistContext, Assists}, utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text, - render_snippet, Cursor, DefaultMethods, + add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, + generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, }, AssistId, AssistKind, }; @@ -168,7 +167,7 @@ fn impl_def_from_trait( // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { - let _ = gen_trait_body(func, trait_path, adt); + let _ = gen_trait_fn_body(func, trait_path, adt); }; Some((impl_def, first_assoc_item)) diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 6552c1feb96..b4b9b6af80d 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs @@ -1,7 +1,7 @@ //! Assorted functions shared by several assists. pub(crate) mod suggest_name; -mod gen_trait_body; +mod gen_trait_fn_body; use std::ops; @@ -26,7 +26,7 @@ use syntax::{ use crate::assist_context::{AssistBuilder, AssistContext}; -pub(crate) use gen_trait_body::gen_trait_body; +pub(crate) use gen_trait_fn_body::gen_trait_fn_body; pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { extract_trivial_expression(&block) diff --git a/crates/ide_assists/src/utils/gen_trait_body.rs b/crates/ide_assists/src/utils/gen_trait_fn_body.rs similarity index 97% rename from crates/ide_assists/src/utils/gen_trait_body.rs rename to crates/ide_assists/src/utils/gen_trait_fn_body.rs index e8d11f42b0e..17e006a7553 100644 --- a/crates/ide_assists/src/utils/gen_trait_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs @@ -1,14 +1,20 @@ //! This module contains functions to generate default trait impl function bodies where possible. -use syntax::ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner}; -use syntax::ted; +use syntax::{ + ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner}, + ted, +}; /// Generate custom trait bodies where possible. /// /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning /// `None` means that generating a custom trait body failed, and the body will remain /// as `todo!` instead. -pub(crate) fn gen_trait_body(func: &ast::Fn, trait_path: &ast::Path, adt: &ast::Adt) -> Option<()> { +pub(crate) fn gen_trait_fn_body( + func: &ast::Fn, + trait_path: &ast::Path, + adt: &ast::Adt, +) -> Option<()> { match trait_path.segment()?.name_ref()?.text().as_str() { "Debug" => gen_debug_impl(adt, func), "Default" => gen_default_impl(adt, func), diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index c895e48f3df..4e99ae67d85 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -280,7 +280,7 @@ fn check_todo(path: &Path, text: &str) { "ast/make.rs", // The documentation in string literals may contain anything for its own purposes "ide_db/src/helpers/generated_lints.rs", - "ide_assists/src/utils/gen_trait_body.rs", + "ide_assists/src/utils/gen_trait_fn_body.rs", "ide_assists/src/tests/generated.rs", ]; if need_todo.iter().any(|p| path.ends_with(p)) {