Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 47e0d07

Browse files
committed
Auto merge of rust-lang#15573 - alibektas:15539/into_to_from, r=Veykril
assist : `into_to_qualified_from` fixes rust-lang#15539. This assist converts an `.into()` call into an explicit fully qualified `from()` call.
2 parents 5ddad87 + 9762f76 commit 47e0d07

File tree

3 files changed

+241
-0
lines changed

3 files changed

+241
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
use hir::{AsAssocItem, HirDisplay};
2+
use ide_db::{
3+
assists::{AssistId, AssistKind},
4+
famous_defs::FamousDefs,
5+
};
6+
use syntax::{ast, AstNode};
7+
8+
use crate::assist_context::{AssistContext, Assists};
9+
10+
// Assist: into_to_qualified_from
11+
//
12+
// Convert an `into` method call to a fully qualified `from` call.
13+
//
14+
// ```
15+
// //- minicore: from
16+
// struct B;
17+
// impl From<i32> for B {
18+
// fn from(a: i32) -> Self {
19+
// B
20+
// }
21+
// }
22+
//
23+
// fn main() -> () {
24+
// let a = 3;
25+
// let b: B = a.in$0to();
26+
// }
27+
// ```
28+
// ->
29+
// ```
30+
// struct B;
31+
// impl From<i32> for B {
32+
// fn from(a: i32) -> Self {
33+
// B
34+
// }
35+
// }
36+
//
37+
// fn main() -> () {
38+
// let a = 3;
39+
// let b: B = B::from(a);
40+
// }
41+
// ```
42+
pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
43+
let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
44+
let nameref = method_call.name_ref()?;
45+
let receiver = method_call.receiver()?;
46+
let db = ctx.db();
47+
let sema = &ctx.sema;
48+
let fnc = sema.resolve_method_call(&method_call)?;
49+
let scope = sema.scope(method_call.syntax())?;
50+
// Check if the method call refers to Into trait.
51+
if fnc.as_assoc_item(db)?.containing_trait_impl(db)?
52+
== FamousDefs(sema, scope.krate()).core_convert_Into()?
53+
{
54+
let type_call = sema.type_of_expr(&method_call.clone().into())?;
55+
let type_call_disp =
56+
type_call.adjusted().display_source_code(db, scope.module().into(), true).ok()?;
57+
58+
acc.add(
59+
AssistId("into_to_qualified_from", AssistKind::Generate),
60+
"Convert `into` to fully qualified `from`",
61+
nameref.syntax().text_range(),
62+
|edit| {
63+
edit.replace(
64+
method_call.syntax().text_range(),
65+
format!("{}::from({})", type_call_disp, receiver),
66+
);
67+
},
68+
);
69+
}
70+
71+
Some(())
72+
}
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use crate::tests::check_assist;
77+
78+
use super::into_to_qualified_from;
79+
80+
#[test]
81+
fn two_types_in_same_mod() {
82+
check_assist(
83+
into_to_qualified_from,
84+
r#"
85+
//- minicore: from
86+
struct A;
87+
struct B;
88+
impl From<A> for B {
89+
fn from(a: A) -> Self {
90+
B
91+
}
92+
}
93+
94+
fn main() -> () {
95+
let a: A = A;
96+
let b: B = a.in$0to();
97+
}"#,
98+
r#"
99+
struct A;
100+
struct B;
101+
impl From<A> for B {
102+
fn from(a: A) -> Self {
103+
B
104+
}
105+
}
106+
107+
fn main() -> () {
108+
let a: A = A;
109+
let b: B = B::from(a);
110+
}"#,
111+
)
112+
}
113+
114+
#[test]
115+
fn fromed_in_child_mod_imported() {
116+
check_assist(
117+
into_to_qualified_from,
118+
r#"
119+
//- minicore: from
120+
use C::B;
121+
122+
struct A;
123+
124+
mod C {
125+
use crate::A;
126+
127+
pub(super) struct B;
128+
impl From<A> for B {
129+
fn from(a: A) -> Self {
130+
B
131+
}
132+
}
133+
}
134+
135+
fn main() -> () {
136+
let a: A = A;
137+
let b: B = a.in$0to();
138+
}"#,
139+
r#"
140+
use C::B;
141+
142+
struct A;
143+
144+
mod C {
145+
use crate::A;
146+
147+
pub(super) struct B;
148+
impl From<A> for B {
149+
fn from(a: A) -> Self {
150+
B
151+
}
152+
}
153+
}
154+
155+
fn main() -> () {
156+
let a: A = A;
157+
let b: B = B::from(a);
158+
}"#,
159+
)
160+
}
161+
162+
#[test]
163+
fn fromed_in_child_mod_not_imported() {
164+
check_assist(
165+
into_to_qualified_from,
166+
r#"
167+
//- minicore: from
168+
struct A;
169+
170+
mod C {
171+
use crate::A;
172+
173+
pub(super) struct B;
174+
impl From<A> for B {
175+
fn from(a: A) -> Self {
176+
B
177+
}
178+
}
179+
}
180+
181+
fn main() -> () {
182+
let a: A = A;
183+
let b: C::B = a.in$0to();
184+
}"#,
185+
r#"
186+
struct A;
187+
188+
mod C {
189+
use crate::A;
190+
191+
pub(super) struct B;
192+
impl From<A> for B {
193+
fn from(a: A) -> Self {
194+
B
195+
}
196+
}
197+
}
198+
199+
fn main() -> () {
200+
let a: A = A;
201+
let b: C::B = C::B::from(a);
202+
}"#,
203+
)
204+
}
205+
}

crates/ide-assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ mod handlers {
211211
mod unwrap_result_return_type;
212212
mod unqualify_method_call;
213213
mod wrap_return_type_in_result;
214+
mod into_to_qualified_from;
214215

215216
pub(crate) fn all() -> &'static [Handler] {
216217
&[
@@ -274,6 +275,7 @@ mod handlers {
274275
inline_local_variable::inline_local_variable,
275276
inline_type_alias::inline_type_alias,
276277
inline_type_alias::inline_type_alias_uses,
278+
into_to_qualified_from::into_to_qualified_from,
277279
introduce_named_generic::introduce_named_generic,
278280
introduce_named_lifetime::introduce_named_lifetime,
279281
invert_if::invert_if,

crates/ide-assists/src/tests/generated.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,40 @@ fn foo() {
17411741
)
17421742
}
17431743

1744+
#[test]
1745+
fn doctest_into_to_qualified_from() {
1746+
check_doc_test(
1747+
"into_to_qualified_from",
1748+
r#####"
1749+
//- minicore: from
1750+
struct B;
1751+
impl From<i32> for B {
1752+
fn from(a: i32) -> Self {
1753+
B
1754+
}
1755+
}
1756+
1757+
fn main() -> () {
1758+
let a = 3;
1759+
let b: B = a.in$0to();
1760+
}
1761+
"#####,
1762+
r#####"
1763+
struct B;
1764+
impl From<i32> for B {
1765+
fn from(a: i32) -> Self {
1766+
B
1767+
}
1768+
}
1769+
1770+
fn main() -> () {
1771+
let a = 3;
1772+
let b: B = B::from(a);
1773+
}
1774+
"#####,
1775+
)
1776+
}
1777+
17441778
#[test]
17451779
fn doctest_introduce_named_generic() {
17461780
check_doc_test(

0 commit comments

Comments
 (0)