]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/call_info.rs
Fix syntax highlighting not highlighting derives anymore
[rust.git] / crates / ide / src / call_info.rs
1 //! This module provides primitives for tracking the information about a call site.
2
3 use either::Either;
4 use hir::{HasAttrs, HirDisplay, Semantics};
5 use ide_db::{active_parameter::callable_for_token, base_db::FilePosition};
6 use stdx::format_to;
7 use syntax::{algo, AstNode, Direction, TextRange, TextSize};
8
9 use crate::RootDatabase;
10
11 /// Contains information about a call site. Specifically the
12 /// `FunctionSignature`and current parameter.
13 #[derive(Debug)]
14 pub struct CallInfo {
15     pub doc: Option<String>,
16     pub signature: String,
17     pub active_parameter: Option<usize>,
18     parameters: Vec<TextRange>,
19 }
20
21 impl CallInfo {
22     pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
23         self.parameters.iter().map(move |&it| &self.signature[it])
24     }
25
26     pub fn parameter_ranges(&self) -> &[TextRange] {
27         &self.parameters
28     }
29
30     fn push_param(&mut self, param: &str) {
31         if !self.signature.ends_with('(') {
32             self.signature.push_str(", ");
33         }
34         let start = TextSize::of(&self.signature);
35         self.signature.push_str(param);
36         let end = TextSize::of(&self.signature);
37         self.parameters.push(TextRange::new(start, end))
38     }
39 }
40
41 /// Computes parameter information for the given call expression.
42 pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
43     let sema = Semantics::new(db);
44     let file = sema.parse(position.file_id);
45     let file = file.syntax();
46     let token = file
47         .token_at_offset(position.offset)
48         .left_biased()
49         // if the cursor is sandwiched between two space tokens and the call is unclosed
50         // this prevents us from leaving the CallExpression
51         .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
52     let token = sema.descend_into_macros_single(token);
53
54     let (callable, active_parameter) = callable_for_token(&sema, token)?;
55
56     let mut res =
57         CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
58
59     match callable.kind() {
60         hir::CallableKind::Function(func) => {
61             res.doc = func.docs(db).map(|it| it.into());
62             format_to!(res.signature, "fn {}", func.name(db));
63         }
64         hir::CallableKind::TupleStruct(strukt) => {
65             res.doc = strukt.docs(db).map(|it| it.into());
66             format_to!(res.signature, "struct {}", strukt.name(db));
67         }
68         hir::CallableKind::TupleEnumVariant(variant) => {
69             res.doc = variant.docs(db).map(|it| it.into());
70             format_to!(
71                 res.signature,
72                 "enum {}::{}",
73                 variant.parent_enum(db).name(db),
74                 variant.name(db)
75             );
76         }
77         hir::CallableKind::Closure => (),
78     }
79
80     res.signature.push('(');
81     {
82         if let Some(self_param) = callable.receiver_param(db) {
83             format_to!(res.signature, "{}", self_param)
84         }
85         let mut buf = String::new();
86         for (pat, ty) in callable.params(db) {
87             buf.clear();
88             if let Some(pat) = pat {
89                 match pat {
90                     Either::Left(_self) => format_to!(buf, "self: "),
91                     Either::Right(pat) => format_to!(buf, "{}: ", pat),
92                 }
93             }
94             format_to!(buf, "{}", ty.display(db));
95             res.push_param(&buf);
96         }
97     }
98     res.signature.push(')');
99
100     match callable.kind() {
101         hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
102             let ret_type = callable.return_type();
103             if !ret_type.is_unit() {
104                 format_to!(res.signature, " -> {}", ret_type.display(db));
105             }
106         }
107         hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
108     }
109     Some(res)
110 }
111
112 #[cfg(test)]
113 mod tests {
114     use expect_test::{expect, Expect};
115     use ide_db::base_db::{fixture::ChangeFixture, FilePosition};
116
117     use crate::RootDatabase;
118
119     /// Creates analysis from a multi-file fixture, returns positions marked with $0.
120     pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
121         let change_fixture = ChangeFixture::parse(ra_fixture);
122         let mut database = RootDatabase::default();
123         database.apply_change(change_fixture.change);
124         let (file_id, range_or_offset) =
125             change_fixture.file_position.expect("expected a marker ($0)");
126         let offset = range_or_offset.expect_offset();
127         (database, FilePosition { file_id, offset })
128     }
129
130     fn check(ra_fixture: &str, expect: Expect) {
131         let (db, position) = position(ra_fixture);
132         let call_info = crate::call_info::call_info(&db, position);
133         let actual = match call_info {
134             Some(call_info) => {
135                 let docs = match &call_info.doc {
136                     None => "".to_string(),
137                     Some(docs) => format!("{}\n------\n", docs.as_str()),
138                 };
139                 let params = call_info
140                     .parameter_labels()
141                     .enumerate()
142                     .map(|(i, param)| {
143                         if Some(i) == call_info.active_parameter {
144                             format!("<{}>", param)
145                         } else {
146                             param.to_string()
147                         }
148                     })
149                     .collect::<Vec<_>>()
150                     .join(", ");
151                 format!("{}{}\n({})\n", docs, call_info.signature, params)
152             }
153             None => String::new(),
154         };
155         expect.assert_eq(&actual);
156     }
157
158     #[test]
159     fn test_fn_signature_two_args() {
160         check(
161             r#"
162 fn foo(x: u32, y: u32) -> u32 {x + y}
163 fn bar() { foo($03, ); }
164 "#,
165             expect![[r#"
166                 fn foo(x: u32, y: u32) -> u32
167                 (<x: u32>, y: u32)
168             "#]],
169         );
170         check(
171             r#"
172 fn foo(x: u32, y: u32) -> u32 {x + y}
173 fn bar() { foo(3$0, ); }
174 "#,
175             expect![[r#"
176                 fn foo(x: u32, y: u32) -> u32
177                 (<x: u32>, y: u32)
178             "#]],
179         );
180         check(
181             r#"
182 fn foo(x: u32, y: u32) -> u32 {x + y}
183 fn bar() { foo(3,$0 ); }
184 "#,
185             expect![[r#"
186                 fn foo(x: u32, y: u32) -> u32
187                 (x: u32, <y: u32>)
188             "#]],
189         );
190         check(
191             r#"
192 fn foo(x: u32, y: u32) -> u32 {x + y}
193 fn bar() { foo(3, $0); }
194 "#,
195             expect![[r#"
196                 fn foo(x: u32, y: u32) -> u32
197                 (x: u32, <y: u32>)
198             "#]],
199         );
200     }
201
202     #[test]
203     fn test_fn_signature_two_args_empty() {
204         check(
205             r#"
206 fn foo(x: u32, y: u32) -> u32 {x + y}
207 fn bar() { foo($0); }
208 "#,
209             expect![[r#"
210                 fn foo(x: u32, y: u32) -> u32
211                 (<x: u32>, y: u32)
212             "#]],
213         );
214     }
215
216     #[test]
217     fn test_fn_signature_two_args_first_generics() {
218         check(
219             r#"
220 fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
221     where T: Copy + Display, U: Debug
222 { x + y }
223
224 fn bar() { foo($03, ); }
225 "#,
226             expect![[r#"
227                 fn foo(x: i32, y: {unknown}) -> u32
228                 (<x: i32>, y: {unknown})
229             "#]],
230         );
231     }
232
233     #[test]
234     fn test_fn_signature_no_params() {
235         check(
236             r#"
237 fn foo<T>() -> T where T: Copy + Display {}
238 fn bar() { foo($0); }
239 "#,
240             expect![[r#"
241                 fn foo() -> {unknown}
242                 ()
243             "#]],
244         );
245     }
246
247     #[test]
248     fn test_fn_signature_for_impl() {
249         check(
250             r#"
251 struct F;
252 impl F { pub fn new() { } }
253 fn bar() {
254     let _ : F = F::new($0);
255 }
256 "#,
257             expect![[r#"
258                 fn new()
259                 ()
260             "#]],
261         );
262     }
263
264     #[test]
265     fn test_fn_signature_for_method_self() {
266         check(
267             r#"
268 struct S;
269 impl S { pub fn do_it(&self) {} }
270
271 fn bar() {
272     let s: S = S;
273     s.do_it($0);
274 }
275 "#,
276             expect![[r#"
277                 fn do_it(&self)
278                 ()
279             "#]],
280         );
281     }
282
283     #[test]
284     fn test_fn_signature_for_method_with_arg() {
285         check(
286             r#"
287 struct S;
288 impl S {
289     fn foo(&self, x: i32) {}
290 }
291
292 fn main() { S.foo($0); }
293 "#,
294             expect![[r#"
295                 fn foo(&self, x: i32)
296                 (<x: i32>)
297             "#]],
298         );
299     }
300
301     #[test]
302     fn test_fn_signature_for_generic_method() {
303         check(
304             r#"
305 struct S<T>(T);
306 impl<T> S<T> {
307     fn foo(&self, x: T) {}
308 }
309
310 fn main() { S(1u32).foo($0); }
311 "#,
312             expect![[r#"
313                 fn foo(&self, x: u32)
314                 (<x: u32>)
315             "#]],
316         );
317     }
318
319     #[test]
320     fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
321         check(
322             r#"
323 struct S;
324 impl S {
325     fn foo(&self, x: i32) {}
326 }
327
328 fn main() { S::foo($0); }
329 "#,
330             expect![[r#"
331                 fn foo(self: &S, x: i32)
332                 (<self: &S>, x: i32)
333             "#]],
334         );
335     }
336
337     #[test]
338     fn test_fn_signature_with_docs_simple() {
339         check(
340             r#"
341 /// test
342 // non-doc-comment
343 fn foo(j: u32) -> u32 {
344     j
345 }
346
347 fn bar() {
348     let _ = foo($0);
349 }
350 "#,
351             expect![[r#"
352             test
353             ------
354             fn foo(j: u32) -> u32
355             (<j: u32>)
356         "#]],
357         );
358     }
359
360     #[test]
361     fn test_fn_signature_with_docs() {
362         check(
363             r#"
364 /// Adds one to the number given.
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// let five = 5;
370 ///
371 /// assert_eq!(6, my_crate::add_one(5));
372 /// ```
373 pub fn add_one(x: i32) -> i32 {
374     x + 1
375 }
376
377 pub fn do() {
378     add_one($0
379 }"#,
380             expect![[r##"
381             Adds one to the number given.
382
383             # Examples
384
385             ```
386             let five = 5;
387
388             assert_eq!(6, my_crate::add_one(5));
389             ```
390             ------
391             fn add_one(x: i32) -> i32
392             (<x: i32>)
393         "##]],
394         );
395     }
396
397     #[test]
398     fn test_fn_signature_with_docs_impl() {
399         check(
400             r#"
401 struct addr;
402 impl addr {
403     /// Adds one to the number given.
404     ///
405     /// # Examples
406     ///
407     /// ```
408     /// let five = 5;
409     ///
410     /// assert_eq!(6, my_crate::add_one(5));
411     /// ```
412     pub fn add_one(x: i32) -> i32 {
413         x + 1
414     }
415 }
416
417 pub fn do_it() {
418     addr {};
419     addr::add_one($0);
420 }
421 "#,
422             expect![[r##"
423             Adds one to the number given.
424
425             # Examples
426
427             ```
428             let five = 5;
429
430             assert_eq!(6, my_crate::add_one(5));
431             ```
432             ------
433             fn add_one(x: i32) -> i32
434             (<x: i32>)
435         "##]],
436         );
437     }
438
439     #[test]
440     fn test_fn_signature_with_docs_from_actix() {
441         check(
442             r#"
443 struct WriteHandler<E>;
444
445 impl<E> WriteHandler<E> {
446     /// Method is called when writer emits error.
447     ///
448     /// If this method returns `ErrorAction::Continue` writer processing
449     /// continues otherwise stream processing stops.
450     fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
451         Running::Stop
452     }
453
454     /// Method is called when writer finishes.
455     ///
456     /// By default this method stops actor's `Context`.
457     fn finished(&mut self, ctx: &mut Self::Context) {
458         ctx.stop()
459     }
460 }
461
462 pub fn foo(mut r: WriteHandler<()>) {
463     r.finished($0);
464 }
465 "#,
466             expect![[r#"
467             Method is called when writer finishes.
468
469             By default this method stops actor's `Context`.
470             ------
471             fn finished(&mut self, ctx: &mut {unknown})
472             (<ctx: &mut {unknown}>)
473         "#]],
474         );
475     }
476
477     #[test]
478     fn call_info_bad_offset() {
479         check(
480             r#"
481 fn foo(x: u32, y: u32) -> u32 {x + y}
482 fn bar() { foo $0 (3, ); }
483 "#,
484             expect![[""]],
485         );
486     }
487
488     #[test]
489     fn test_nested_method_in_lambda() {
490         check(
491             r#"
492 struct Foo;
493 impl Foo { fn bar(&self, _: u32) { } }
494
495 fn bar(_: u32) { }
496
497 fn main() {
498     let foo = Foo;
499     std::thread::spawn(move || foo.bar($0));
500 }
501 "#,
502             expect![[r#"
503                 fn bar(&self, _: u32)
504                 (<_: u32>)
505             "#]],
506         );
507     }
508
509     #[test]
510     fn works_for_tuple_structs() {
511         check(
512             r#"
513 /// A cool tuple struct
514 struct S(u32, i32);
515 fn main() {
516     let s = S(0, $0);
517 }
518 "#,
519             expect![[r#"
520             A cool tuple struct
521             ------
522             struct S(u32, i32)
523             (u32, <i32>)
524         "#]],
525         );
526     }
527
528     #[test]
529     fn generic_struct() {
530         check(
531             r#"
532 struct S<T>(T);
533 fn main() {
534     let s = S($0);
535 }
536 "#,
537             expect![[r#"
538                 struct S({unknown})
539                 (<{unknown}>)
540             "#]],
541         );
542     }
543
544     #[test]
545     fn works_for_enum_variants() {
546         check(
547             r#"
548 enum E {
549     /// A Variant
550     A(i32),
551     /// Another
552     B,
553     /// And C
554     C { a: i32, b: i32 }
555 }
556
557 fn main() {
558     let a = E::A($0);
559 }
560 "#,
561             expect![[r#"
562             A Variant
563             ------
564             enum E::A(i32)
565             (<i32>)
566         "#]],
567         );
568     }
569
570     #[test]
571     fn cant_call_struct_record() {
572         check(
573             r#"
574 struct S { x: u32, y: i32 }
575 fn main() {
576     let s = S($0);
577 }
578 "#,
579             expect![[""]],
580         );
581     }
582
583     #[test]
584     fn cant_call_enum_record() {
585         check(
586             r#"
587 enum E {
588     /// A Variant
589     A(i32),
590     /// Another
591     B,
592     /// And C
593     C { a: i32, b: i32 }
594 }
595
596 fn main() {
597     let a = E::C($0);
598 }
599 "#,
600             expect![[""]],
601         );
602     }
603
604     #[test]
605     fn fn_signature_for_call_in_macro() {
606         check(
607             r#"
608 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
609 fn foo() { }
610 id! {
611     fn bar() { foo($0); }
612 }
613 "#,
614             expect![[r#"
615                 fn foo()
616                 ()
617             "#]],
618         );
619     }
620
621     #[test]
622     fn call_info_for_lambdas() {
623         check(
624             r#"
625 struct S;
626 fn foo(s: S) -> i32 { 92 }
627 fn main() {
628     (|s| foo(s))($0)
629 }
630         "#,
631             expect![[r#"
632                 (S) -> i32
633                 (<S>)
634             "#]],
635         )
636     }
637
638     #[test]
639     fn call_info_for_fn_ptr() {
640         check(
641             r#"
642 fn main(f: fn(i32, f64) -> char) {
643     f(0, $0)
644 }
645         "#,
646             expect![[r#"
647                 (i32, f64) -> char
648                 (i32, <f64>)
649             "#]],
650         )
651     }
652
653     #[test]
654     fn call_info_for_unclosed_call() {
655         check(
656             r#"
657 fn foo(foo: u32, bar: u32) {}
658 fn main() {
659     foo($0
660 }"#,
661             expect![[r#"
662             fn foo(foo: u32, bar: u32)
663             (<foo: u32>, bar: u32)
664         "#]],
665         );
666         // check with surrounding space
667         check(
668             r#"
669 fn foo(foo: u32, bar: u32) {}
670 fn main() {
671     foo( $0
672 }"#,
673             expect![[r#"
674             fn foo(foo: u32, bar: u32)
675             (<foo: u32>, bar: u32)
676         "#]],
677         )
678     }
679 }