]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs
Rollup merge of #98391 - joboet:sgx_parker, r=m-ou-se
[rust.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / qualify_method_call.rs
1 use hir::{db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, ItemInNs, ModuleDef};
2 use ide_db::assists::{AssistId, AssistKind};
3 use syntax::{ast, AstNode};
4
5 use crate::{
6     assist_context::{AssistContext, Assists},
7     handlers::qualify_path::QualifyCandidate,
8 };
9
10 // Assist: qualify_method_call
11 //
12 // Replaces the method call with a qualified function call.
13 //
14 // ```
15 // struct Foo;
16 // impl Foo {
17 //     fn foo(&self) {}
18 // }
19 // fn main() {
20 //     let foo = Foo;
21 //     foo.fo$0o();
22 // }
23 // ```
24 // ->
25 // ```
26 // struct Foo;
27 // impl Foo {
28 //     fn foo(&self) {}
29 // }
30 // fn main() {
31 //     let foo = Foo;
32 //     Foo::foo(&foo);
33 // }
34 // ```
35 pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
36     let name: ast::NameRef = ctx.find_node_at_offset()?;
37     let call = name.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
38
39     let ident = name.ident_token()?;
40
41     let range = call.syntax().text_range();
42     let resolved_call = ctx.sema.resolve_method_call(&call)?;
43
44     let current_module = ctx.sema.scope(call.syntax())?.module();
45     let target_module_def = ModuleDef::from(resolved_call);
46     let item_in_ns = ItemInNs::from(target_module_def);
47     let receiver_path = current_module.find_use_path(
48         ctx.sema.db,
49         item_for_path_search(ctx.sema.db, item_in_ns)?,
50         ctx.config.prefer_no_std,
51     )?;
52
53     let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
54
55     acc.add(
56         AssistId("qualify_method_call", AssistKind::RefactorInline),
57         format!("Qualify `{ident}` method call"),
58         range,
59         |builder| {
60             qualify_candidate.qualify(
61                 |replace_with: String| builder.replace(range, replace_with),
62                 &receiver_path,
63                 item_in_ns,
64             )
65         },
66     );
67     Some(())
68 }
69
70 fn item_for_path_search(db: &dyn HirDatabase, item: ItemInNs) -> Option<ItemInNs> {
71     Some(match item {
72         ItemInNs::Types(_) | ItemInNs::Values(_) => match item_as_assoc(db, item) {
73             Some(assoc_item) => match assoc_item.container(db) {
74                 AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
75                 AssocItemContainer::Impl(impl_) => match impl_.trait_(db) {
76                     None => ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?)),
77                     Some(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
78                 },
79             },
80             None => item,
81         },
82         ItemInNs::Macros(_) => item,
83     })
84 }
85
86 fn item_as_assoc(db: &dyn HirDatabase, item: ItemInNs) -> Option<AssocItem> {
87     item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db))
88 }
89
90 #[cfg(test)]
91 mod tests {
92     use super::*;
93     use crate::tests::{check_assist, check_assist_not_applicable};
94
95     #[test]
96     fn struct_method() {
97         check_assist(
98             qualify_method_call,
99             r#"
100 struct Foo;
101 impl Foo {
102     fn foo(&self) {}
103 }
104
105 fn main() {
106     let foo = Foo {};
107     foo.fo$0o()
108 }
109 "#,
110             r#"
111 struct Foo;
112 impl Foo {
113     fn foo(&self) {}
114 }
115
116 fn main() {
117     let foo = Foo {};
118     Foo::foo(&foo)
119 }
120 "#,
121         );
122     }
123
124     #[test]
125     fn struct_method_multi_params() {
126         check_assist(
127             qualify_method_call,
128             r#"
129 struct Foo;
130 impl Foo {
131     fn foo(&self, p1: i32, p2: u32) {}
132 }
133
134 fn main() {
135     let foo = Foo {};
136     foo.fo$0o(9, 9u)
137 }
138 "#,
139             r#"
140 struct Foo;
141 impl Foo {
142     fn foo(&self, p1: i32, p2: u32) {}
143 }
144
145 fn main() {
146     let foo = Foo {};
147     Foo::foo(&foo, 9, 9u)
148 }
149 "#,
150         );
151     }
152
153     #[test]
154     fn struct_method_consume() {
155         check_assist(
156             qualify_method_call,
157             r#"
158 struct Foo;
159 impl Foo {
160     fn foo(self, p1: i32, p2: u32) {}
161 }
162
163 fn main() {
164     let foo = Foo {};
165     foo.fo$0o(9, 9u)
166 }
167 "#,
168             r#"
169 struct Foo;
170 impl Foo {
171     fn foo(self, p1: i32, p2: u32) {}
172 }
173
174 fn main() {
175     let foo = Foo {};
176     Foo::foo(foo, 9, 9u)
177 }
178 "#,
179         );
180     }
181
182     #[test]
183     fn struct_method_exclusive() {
184         check_assist(
185             qualify_method_call,
186             r#"
187 struct Foo;
188 impl Foo {
189     fn foo(&mut self, p1: i32, p2: u32) {}
190 }
191
192 fn main() {
193     let foo = Foo {};
194     foo.fo$0o(9, 9u)
195 }
196 "#,
197             r#"
198 struct Foo;
199 impl Foo {
200     fn foo(&mut self, p1: i32, p2: u32) {}
201 }
202
203 fn main() {
204     let foo = Foo {};
205     Foo::foo(&mut foo, 9, 9u)
206 }
207 "#,
208         );
209     }
210
211     #[test]
212     fn struct_method_cross_crate() {
213         check_assist(
214             qualify_method_call,
215             r#"
216 //- /main.rs crate:main deps:dep
217 fn main() {
218     let foo = dep::test_mod::Foo {};
219     foo.fo$0o(9, 9u)
220 }
221 //- /dep.rs crate:dep
222 pub mod test_mod {
223     pub struct Foo;
224     impl Foo {
225         pub fn foo(&mut self, p1: i32, p2: u32) {}
226     }
227 }
228 "#,
229             r#"
230 fn main() {
231     let foo = dep::test_mod::Foo {};
232     dep::test_mod::Foo::foo(&mut foo, 9, 9u)
233 }
234 "#,
235         );
236     }
237
238     #[test]
239     fn struct_method_generic() {
240         check_assist(
241             qualify_method_call,
242             r#"
243 struct Foo;
244 impl Foo {
245     fn foo<T>(&self) {}
246 }
247
248 fn main() {
249     let foo = Foo {};
250     foo.fo$0o::<()>()
251 }
252 "#,
253             r#"
254 struct Foo;
255 impl Foo {
256     fn foo<T>(&self) {}
257 }
258
259 fn main() {
260     let foo = Foo {};
261     Foo::foo::<()>(&foo)
262 }
263 "#,
264         );
265     }
266
267     #[test]
268     fn trait_method() {
269         check_assist(
270             qualify_method_call,
271             r#"
272 mod test_mod {
273     pub trait TestTrait {
274         fn test_method(&self);
275     }
276     pub struct TestStruct {}
277     impl TestTrait for TestStruct {
278         fn test_method(&self) {}
279     }
280 }
281
282 use test_mod::*;
283
284 fn main() {
285     let test_struct = test_mod::TestStruct {};
286     test_struct.test_meth$0od()
287 }
288 "#,
289             r#"
290 mod test_mod {
291     pub trait TestTrait {
292         fn test_method(&self);
293     }
294     pub struct TestStruct {}
295     impl TestTrait for TestStruct {
296         fn test_method(&self) {}
297     }
298 }
299
300 use test_mod::*;
301
302 fn main() {
303     let test_struct = test_mod::TestStruct {};
304     TestTrait::test_method(&test_struct)
305 }
306 "#,
307         );
308     }
309
310     #[test]
311     fn trait_method_multi_params() {
312         check_assist(
313             qualify_method_call,
314             r#"
315 mod test_mod {
316     pub trait TestTrait {
317         fn test_method(&self, p1: i32, p2: u32);
318     }
319     pub struct TestStruct {}
320     impl TestTrait for TestStruct {
321         fn test_method(&self, p1: i32, p2: u32) {}
322     }
323 }
324
325 use test_mod::*;
326
327 fn main() {
328     let test_struct = test_mod::TestStruct {};
329     test_struct.test_meth$0od(12, 32u)
330 }
331 "#,
332             r#"
333 mod test_mod {
334     pub trait TestTrait {
335         fn test_method(&self, p1: i32, p2: u32);
336     }
337     pub struct TestStruct {}
338     impl TestTrait for TestStruct {
339         fn test_method(&self, p1: i32, p2: u32) {}
340     }
341 }
342
343 use test_mod::*;
344
345 fn main() {
346     let test_struct = test_mod::TestStruct {};
347     TestTrait::test_method(&test_struct, 12, 32u)
348 }
349 "#,
350         );
351     }
352
353     #[test]
354     fn trait_method_consume() {
355         check_assist(
356             qualify_method_call,
357             r#"
358 mod test_mod {
359     pub trait TestTrait {
360         fn test_method(self, p1: i32, p2: u32);
361     }
362     pub struct TestStruct {}
363     impl TestTrait for TestStruct {
364         fn test_method(self, p1: i32, p2: u32) {}
365     }
366 }
367
368 use test_mod::*;
369
370 fn main() {
371     let test_struct = test_mod::TestStruct {};
372     test_struct.test_meth$0od(12, 32u)
373 }
374 "#,
375             r#"
376 mod test_mod {
377     pub trait TestTrait {
378         fn test_method(self, p1: i32, p2: u32);
379     }
380     pub struct TestStruct {}
381     impl TestTrait for TestStruct {
382         fn test_method(self, p1: i32, p2: u32) {}
383     }
384 }
385
386 use test_mod::*;
387
388 fn main() {
389     let test_struct = test_mod::TestStruct {};
390     TestTrait::test_method(test_struct, 12, 32u)
391 }
392 "#,
393         );
394     }
395
396     #[test]
397     fn trait_method_exclusive() {
398         check_assist(
399             qualify_method_call,
400             r#"
401 mod test_mod {
402     pub trait TestTrait {
403         fn test_method(&mut self, p1: i32, p2: u32);
404     }
405     pub struct TestStruct {}
406     impl TestTrait for TestStruct {
407         fn test_method(&mut self, p1: i32, p2: u32);
408     }
409 }
410
411 use test_mod::*;
412
413 fn main() {
414     let test_struct = test_mod::TestStruct {};
415     test_struct.test_meth$0od(12, 32u)
416 }
417 "#,
418             r#"
419 mod test_mod {
420     pub trait TestTrait {
421         fn test_method(&mut self, p1: i32, p2: u32);
422     }
423     pub struct TestStruct {}
424     impl TestTrait for TestStruct {
425         fn test_method(&mut self, p1: i32, p2: u32);
426     }
427 }
428
429 use test_mod::*;
430
431 fn main() {
432     let test_struct = test_mod::TestStruct {};
433     TestTrait::test_method(&mut test_struct, 12, 32u)
434 }
435 "#,
436         );
437     }
438
439     #[test]
440     fn trait_method_cross_crate() {
441         check_assist(
442             qualify_method_call,
443             r#"
444 //- /main.rs crate:main deps:dep
445 fn main() {
446     let foo = dep::test_mod::Foo {};
447     foo.fo$0o(9, 9u)
448 }
449 //- /dep.rs crate:dep
450 pub mod test_mod {
451     pub struct Foo;
452     impl Foo {
453         pub fn foo(&mut self, p1: i32, p2: u32) {}
454     }
455 }
456 "#,
457             r#"
458 fn main() {
459     let foo = dep::test_mod::Foo {};
460     dep::test_mod::Foo::foo(&mut foo, 9, 9u)
461 }
462 "#,
463         );
464     }
465
466     #[test]
467     fn trait_method_generic() {
468         check_assist(
469             qualify_method_call,
470             r#"
471 mod test_mod {
472     pub trait TestTrait {
473         fn test_method<T>(&self);
474     }
475     pub struct TestStruct {}
476     impl TestTrait for TestStruct {
477         fn test_method<T>(&self) {}
478     }
479 }
480
481 use test_mod::*;
482
483 fn main() {
484     let test_struct = TestStruct {};
485     test_struct.test_meth$0od::<()>()
486 }
487 "#,
488             r#"
489 mod test_mod {
490     pub trait TestTrait {
491         fn test_method<T>(&self);
492     }
493     pub struct TestStruct {}
494     impl TestTrait for TestStruct {
495         fn test_method<T>(&self) {}
496     }
497 }
498
499 use test_mod::*;
500
501 fn main() {
502     let test_struct = TestStruct {};
503     TestTrait::test_method::<()>(&test_struct)
504 }
505 "#,
506         );
507     }
508
509     #[test]
510     fn struct_method_over_stuct_instance() {
511         check_assist_not_applicable(
512             qualify_method_call,
513             r#"
514 struct Foo;
515 impl Foo {
516     fn foo(&self) {}
517 }
518
519 fn main() {
520     let foo = Foo {};
521     f$0oo.foo()
522 }
523 "#,
524         );
525     }
526
527     #[test]
528     fn trait_method_over_stuct_instance() {
529         check_assist_not_applicable(
530             qualify_method_call,
531             r#"
532 mod test_mod {
533     pub trait TestTrait {
534         fn test_method(&self);
535     }
536     pub struct TestStruct {}
537     impl TestTrait for TestStruct {
538         fn test_method(&self) {}
539     }
540 }
541
542 use test_mod::*;
543
544 fn main() {
545     let test_struct = test_mod::TestStruct {};
546     tes$0t_struct.test_method()
547 }
548 "#,
549         );
550     }
551 }