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