2 helpers::{mod_path_to_ast, FamousDefs},
3 traits::resolve_target_trait,
5 use syntax::ast::{self, AstNode, NameOwner};
7 use crate::{AssistContext, AssistId, AssistKind, Assists};
9 // FIXME: this should be a diagnostic
11 // Assist: convert_into_to_from
13 // Converts an Into impl to an equivalent From impl.
16 // # //- /lib.rs crate:core
17 // # pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } }
18 // # //- /lib.rs crate:main deps:core
19 // # use core::convert::Into;
20 // impl $0Into<Thing> for usize {
21 // fn into(self) -> Thing {
23 // b: self.to_string(),
31 // # use core::convert::Into;
32 // impl From<usize> for Thing {
33 // fn from(val: usize) -> Self {
35 // b: val.to_string(),
41 pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42 let impl_ = ctx.find_node_at_offset::<ast::Impl>()?;
43 let src_type = impl_.self_ty()?;
44 let ast_trait = impl_.trait_()?;
46 let module = ctx.sema.scope(impl_.syntax()).module()?;
48 let trait_ = resolve_target_trait(&ctx.sema, &impl_)?;
49 if trait_ != FamousDefs(&ctx.sema, Some(module.krate())).core_convert_Into()? {
54 let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?;
55 let src_type_def = match ctx.sema.resolve_path(&src_type_path) {
56 Some(hir::PathResolution::Def(module_def)) => module_def,
60 mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
63 let dest_type = match &ast_trait {
64 ast::Type::PathType(path) => {
65 path.path()?.segment()?.generic_arg_list()?.generic_args().next()?
70 let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| {
71 if let ast::AssocItem::Fn(f) = item {
72 if f.name()?.text() == "into" {
79 let into_fn_name = into_fn.name()?;
80 let into_fn_params = into_fn.param_list()?;
81 let into_fn_return = into_fn.ret_type()?;
87 .filter_map(ast::NameRef::cast)
88 .filter(|name| name.text() == "self" || name.text() == "Self");
91 AssistId("convert_into_to_from", AssistKind::RefactorRewrite),
92 "Convert Into to From",
93 impl_.syntax().text_range(),
95 builder.replace(src_type.syntax().text_range(), dest_type.to_string());
96 builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type));
97 builder.replace(into_fn_return.syntax().text_range(), "-> Self");
99 into_fn_params.syntax().text_range(),
100 format!("(val: {})", src_type.to_string()),
102 builder.replace(into_fn_name.syntax().text_range(), "from");
105 match s.text().as_ref() {
106 "self" => builder.replace(s.syntax().text_range(), "val"),
107 "Self" => builder.replace(s.syntax().text_range(), src_type_path.to_string()),
119 use crate::tests::{check_assist, check_assist_not_applicable};
122 fn convert_into_to_from_converts_a_struct() {
124 convert_into_to_from,
132 impl $0core::convert::Into<Thing> for usize {
133 fn into(self) -> Thing {
147 impl From<usize> for Thing {
148 fn from(val: usize) -> Self {
160 fn convert_into_to_from_converts_enums() {
162 convert_into_to_from,
170 impl $0core::convert::Into<String> for Thing {
171 fn into(self) -> String {
185 impl From<Thing> for String {
186 fn from(val: Thing) -> Self {
198 fn convert_into_to_from_on_enum_with_lifetimes() {
200 convert_into_to_from,
208 impl<'a> $0core::convert::Into<&'a str> for Thing<'a> {
209 fn into(self) -> &'a str {
223 impl<'a> From<Thing<'a>> for &'a str {
224 fn from(val: Thing<'a>) -> Self {
236 fn convert_into_to_from_works_on_references() {
238 convert_into_to_from,
241 struct Thing(String);
243 impl $0core::convert::Into<String> for &Thing {
244 fn into(self) -> Thing {
250 struct Thing(String);
252 impl From<&Thing> for String {
253 fn from(val: &Thing) -> Self {
262 fn convert_into_to_from_works_on_qualified_structs() {
264 convert_into_to_from,
268 pub struct Thing(String);
269 pub struct BetterThing(String);
272 impl $0core::convert::Into<things::BetterThing> for &things::Thing {
273 fn into(self) -> Thing {
274 things::BetterThing(self.0.clone())
280 pub struct Thing(String);
281 pub struct BetterThing(String);
284 impl From<&things::Thing> for things::BetterThing {
285 fn from(val: &things::Thing) -> Self {
286 things::BetterThing(val.0.clone())
294 fn convert_into_to_from_works_on_qualified_enums() {
296 convert_into_to_from,
303 pub struct BetterThing {
308 impl $0core::convert::Into<things::BetterThing> for &things::Thing {
309 fn into(self) -> Thing {
311 Self::A(s) => things::BetterThing::B(s)
321 pub struct BetterThing {
326 impl From<&things::Thing> for things::BetterThing {
327 fn from(val: &things::Thing) -> Self {
329 things::Thing::A(s) => things::BetterThing::B(s)
338 fn convert_into_to_from_not_applicable_on_any_trait_named_into() {
339 check_assist_not_applicable(
340 convert_into_to_from,
344 pub fn into(self) -> T;
351 impl $0Into<Thing> for String {
352 fn into(self) -> Thing {