ide_assists/handlers/
into_to_qualified_from.rs
1use hir::{AsAssocItem, HirDisplay};
2use ide_db::{assists::AssistId, famous_defs::FamousDefs};
3use syntax::{AstNode, ast};
4
5use crate::assist_context::{AssistContext, Assists};
6
7pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
40 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
41 let nameref = method_call.name_ref()?;
42 let receiver = method_call.receiver()?;
43 let db = ctx.db();
44 let sema = &ctx.sema;
45 let fnc = sema.resolve_method_call(&method_call)?;
46 let scope = sema.scope(method_call.syntax())?;
47 if fnc.as_assoc_item(db)?.implemented_trait(db)?
49 == FamousDefs(sema, scope.krate()).core_convert_Into()?
50 {
51 let type_call = sema.type_of_expr(&method_call.clone().into())?;
52 let adjusted_tc = type_call.adjusted();
53
54 if adjusted_tc.contains_unknown() {
55 return None;
56 }
57
58 let sc = adjusted_tc.display_source_code(db, scope.module().into(), true).ok()?;
59 acc.add(
60 AssistId::generate("into_to_qualified_from"),
61 "Convert `into` to fully qualified `from`",
62 nameref.syntax().text_range(),
63 |edit| {
64 edit.replace(
65 method_call.syntax().text_range(),
66 if sc.chars().all(|c| c.is_alphanumeric() || c == ':') {
67 format!("{sc}::from({receiver})")
68 } else {
69 format!("<{sc}>::from({receiver})")
70 },
71 );
72 },
73 );
74 }
75
76 Some(())
77}
78
79#[cfg(test)]
80mod tests {
81 use crate::tests::check_assist;
82
83 use super::into_to_qualified_from;
84
85 #[test]
86 fn two_types_in_same_mod() {
87 check_assist(
88 into_to_qualified_from,
89 r#"
90//- minicore: from
91struct A;
92struct B;
93impl From<A> for B {
94 fn from(a: A) -> Self {
95 B
96 }
97}
98
99fn main() -> () {
100 let a: A = A;
101 let b: B = a.in$0to();
102}"#,
103 r#"
104struct A;
105struct B;
106impl From<A> for B {
107 fn from(a: A) -> Self {
108 B
109 }
110}
111
112fn main() -> () {
113 let a: A = A;
114 let b: B = B::from(a);
115}"#,
116 )
117 }
118
119 #[test]
120 fn from_in_child_mod_imported() {
121 check_assist(
122 into_to_qualified_from,
123 r#"
124//- minicore: from
125use C::B;
126
127struct A;
128
129mod C {
130 use crate::A;
131
132 pub(super) struct B;
133 impl From<A> for B {
134 fn from(a: A) -> Self {
135 B
136 }
137 }
138}
139
140fn main() -> () {
141 let a: A = A;
142 let b: B = a.in$0to();
143}"#,
144 r#"
145use C::B;
146
147struct A;
148
149mod C {
150 use crate::A;
151
152 pub(super) struct B;
153 impl From<A> for B {
154 fn from(a: A) -> Self {
155 B
156 }
157 }
158}
159
160fn main() -> () {
161 let a: A = A;
162 let b: B = B::from(a);
163}"#,
164 )
165 }
166
167 #[test]
168 fn from_in_child_mod_not_imported() {
169 check_assist(
170 into_to_qualified_from,
171 r#"
172//- minicore: from
173struct A;
174
175mod C {
176 use crate::A;
177
178 pub(super) struct B;
179 impl From<A> for B {
180 fn from(a: A) -> Self {
181 B
182 }
183 }
184}
185
186fn main() -> () {
187 let a: A = A;
188 let b: C::B = a.in$0to();
189}"#,
190 r#"
191struct A;
192
193mod C {
194 use crate::A;
195
196 pub(super) struct B;
197 impl From<A> for B {
198 fn from(a: A) -> Self {
199 B
200 }
201 }
202}
203
204fn main() -> () {
205 let a: A = A;
206 let b: C::B = C::B::from(a);
207}"#,
208 )
209 }
210
211 #[test]
212 fn preceding_type_qualifier() {
213 check_assist(
214 into_to_qualified_from,
215 r#"
216//- minicore: from
217impl From<(i32,i32)> for [i32;2] {
218 fn from(value: (i32,i32)) -> Self {
219 [value.0, value.1]
220 }
221}
222
223fn tuple_to_array() -> [i32; 2] {
224 (0,1).in$0to()
225}"#,
226 r#"
227impl From<(i32,i32)> for [i32;2] {
228 fn from(value: (i32,i32)) -> Self {
229 [value.0, value.1]
230 }
231}
232
233fn tuple_to_array() -> [i32; 2] {
234 <[i32; 2]>::from((0,1))
235}"#,
236 )
237 }
238
239 #[test]
240 fn type_with_gens() {
241 check_assist(
242 into_to_qualified_from,
243 r#"
244//- minicore: from
245struct StructA<Gen>(Gen);
246
247impl From<i32> for StructA<i32> {
248 fn from(value: i32) -> Self {
249 StructA(value + 1)
250 }
251}
252
253fn main() -> () {
254 let a: StructA<i32> = 3.in$0to();
255}"#,
256 r#"
257struct StructA<Gen>(Gen);
258
259impl From<i32> for StructA<i32> {
260 fn from(value: i32) -> Self {
261 StructA(value + 1)
262 }
263}
264
265fn main() -> () {
266 let a: StructA<i32> = <StructA<i32>>::from(3);
267}"#,
268 )
269 }
270}