]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/inlay_hints.rs
e3d63cc949e1d81c72233323381a149a9be31727
[rust.git] / crates / ide / src / inlay_hints.rs
1 use either::Either;
2 use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
3 use ide_db::helpers::FamousDefs;
4 use ide_db::RootDatabase;
5 use stdx::to_lower_snake_case;
6 use syntax::{
7     ast::{self, ArgListOwner, AstNode, NameOwner},
8     match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
9 };
10
11 use crate::FileId;
12
13 #[derive(Clone, Debug, PartialEq, Eq)]
14 pub struct InlayHintsConfig {
15     pub type_hints: bool,
16     pub parameter_hints: bool,
17     pub chaining_hints: bool,
18     pub max_length: Option<usize>,
19 }
20
21 #[derive(Clone, Debug, PartialEq, Eq)]
22 pub enum InlayKind {
23     TypeHint,
24     ParameterHint,
25     ChainingHint,
26 }
27
28 #[derive(Debug)]
29 pub struct InlayHint {
30     pub range: TextRange,
31     pub kind: InlayKind,
32     pub label: SmolStr,
33 }
34
35 // Feature: Inlay Hints
36 //
37 // rust-analyzer shows additional information inline with the source code.
38 // Editors usually render this using read-only virtual text snippets interspersed with code.
39 //
40 // rust-analyzer shows hints for
41 //
42 // * types of local variables
43 // * names of function arguments
44 // * types of chained expressions
45 //
46 // **Note:** VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations.
47 // This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird:
48 // https://github.com/rust-analyzer/rust-analyzer/issues/1623[1], https://github.com/rust-analyzer/rust-analyzer/issues/3453[2].
49 //
50 // |===
51 // | Editor  | Action Name
52 //
53 // | VS Code | **Rust Analyzer: Toggle inlay hints*
54 // |===
55 //
56 // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
57 pub(crate) fn inlay_hints(
58     db: &RootDatabase,
59     file_id: FileId,
60     config: &InlayHintsConfig,
61 ) -> Vec<InlayHint> {
62     let _p = profile::span("inlay_hints");
63     let sema = Semantics::new(db);
64     let file = sema.parse(file_id);
65
66     let mut res = Vec::new();
67     for node in file.syntax().descendants() {
68         if let Some(expr) = ast::Expr::cast(node.clone()) {
69             get_chaining_hints(&mut res, &sema, config, expr);
70         }
71
72         match_ast! {
73             match node {
74                 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
75                 ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
76                 ast::IdentPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); },
77                 _ => (),
78             }
79         }
80     }
81     res
82 }
83
84 fn get_chaining_hints(
85     acc: &mut Vec<InlayHint>,
86     sema: &Semantics<RootDatabase>,
87     config: &InlayHintsConfig,
88     expr: ast::Expr,
89 ) -> Option<()> {
90     if !config.chaining_hints {
91         return None;
92     }
93
94     if matches!(expr, ast::Expr::RecordExpr(_)) {
95         return None;
96     }
97
98     let krate = sema.scope(expr.syntax()).module().map(|it| it.krate());
99     let famous_defs = FamousDefs(sema, krate);
100
101     let mut tokens = expr
102         .syntax()
103         .siblings_with_tokens(Direction::Next)
104         .filter_map(NodeOrToken::into_token)
105         .filter(|t| match t.kind() {
106             SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
107             SyntaxKind::COMMENT => false,
108             _ => true,
109         });
110
111     // Chaining can be defined as an expression whose next sibling tokens are newline and dot
112     // Ignoring extra whitespace and comments
113     let next = tokens.next()?.kind();
114     if next == SyntaxKind::WHITESPACE {
115         let mut next_next = tokens.next()?.kind();
116         while next_next == SyntaxKind::WHITESPACE {
117             next_next = tokens.next()?.kind();
118         }
119         if next_next == T![.] {
120             let ty = sema.type_of_expr(&expr)?.original;
121             if ty.is_unknown() {
122                 return None;
123             }
124             if matches!(expr, ast::Expr::PathExpr(_)) {
125                 if let Some(hir::Adt::Struct(st)) = ty.as_adt() {
126                     if st.fields(sema.db).is_empty() {
127                         return None;
128                     }
129                 }
130             }
131             acc.push(InlayHint {
132                 range: expr.syntax().text_range(),
133                 kind: InlayKind::ChainingHint,
134                 label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
135                     ty.display_truncated(sema.db, config.max_length).to_string().into()
136                 }),
137             });
138         }
139     }
140     Some(())
141 }
142
143 fn get_param_name_hints(
144     acc: &mut Vec<InlayHint>,
145     sema: &Semantics<RootDatabase>,
146     config: &InlayHintsConfig,
147     expr: ast::Expr,
148 ) -> Option<()> {
149     if !config.parameter_hints {
150         return None;
151     }
152
153     let (callable, arg_list) = get_callable(sema, &expr)?;
154     let hints = callable
155         .params(sema.db)
156         .into_iter()
157         .zip(arg_list.args())
158         .filter_map(|((param, _ty), arg)| {
159             let param_name = match param? {
160                 Either::Left(_) => "self".to_string(),
161                 Either::Right(pat) => match pat {
162                     ast::Pat::IdentPat(it) => it.name()?.to_string(),
163                     _ => return None,
164                 },
165             };
166             Some((param_name, arg))
167         })
168         .filter(|(param_name, arg)| !should_hide_param_name_hint(sema, &callable, param_name, arg))
169         .map(|(param_name, arg)| InlayHint {
170             range: arg.syntax().text_range(),
171             kind: InlayKind::ParameterHint,
172             label: param_name.into(),
173         });
174
175     acc.extend(hints);
176     Some(())
177 }
178
179 fn get_bind_pat_hints(
180     acc: &mut Vec<InlayHint>,
181     sema: &Semantics<RootDatabase>,
182     config: &InlayHintsConfig,
183     pat: ast::IdentPat,
184 ) -> Option<()> {
185     if !config.type_hints {
186         return None;
187     }
188
189     let krate = sema.scope(pat.syntax()).module().map(|it| it.krate());
190     let famous_defs = FamousDefs(sema, krate);
191
192     let ty = sema.type_of_pat(&pat.clone().into())?.original;
193
194     if should_not_display_type_hint(sema, &pat, &ty) {
195         return None;
196     }
197
198     acc.push(InlayHint {
199         range: match pat.name() {
200             Some(name) => name.syntax().text_range(),
201             None => pat.syntax().text_range(),
202         },
203         kind: InlayKind::TypeHint,
204         label: hint_iterator(sema, &famous_defs, config, &ty)
205             .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string().into()),
206     });
207
208     Some(())
209 }
210
211 /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
212 fn hint_iterator(
213     sema: &Semantics<RootDatabase>,
214     famous_defs: &FamousDefs,
215     config: &InlayHintsConfig,
216     ty: &hir::Type,
217 ) -> Option<SmolStr> {
218     let db = sema.db;
219     let strukt = ty.strip_references().as_adt()?;
220     let krate = strukt.module(db).krate();
221     if krate != famous_defs.core()? {
222         return None;
223     }
224     let iter_trait = famous_defs.core_iter_Iterator()?;
225     let iter_mod = famous_defs.core_iter()?;
226
227     // Assert that this struct comes from `core::iter`.
228     if !(strukt.visibility(db) == hir::Visibility::Public
229         && strukt.module(db).path_to_root(db).contains(&iter_mod))
230     {
231         return None;
232     }
233
234     if ty.impls_trait(db, iter_trait, &[]) {
235         let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
236             hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
237             _ => None,
238         })?;
239         if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
240             const LABEL_START: &str = "impl Iterator<Item = ";
241             const LABEL_END: &str = ">";
242
243             let ty_display = hint_iterator(sema, famous_defs, config, &ty)
244                 .map(|assoc_type_impl| assoc_type_impl.to_string())
245                 .unwrap_or_else(|| {
246                     ty.display_truncated(
247                         db,
248                         config
249                             .max_length
250                             .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
251                     )
252                     .to_string()
253                 });
254             return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into());
255         }
256     }
257
258     None
259 }
260
261 fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool {
262     if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() {
263         let pat_text = bind_pat.to_string();
264         enum_data
265             .variants(db)
266             .into_iter()
267             .map(|variant| variant.name(db).to_string())
268             .any(|enum_name| enum_name == pat_text)
269     } else {
270         false
271     }
272 }
273
274 fn should_not_display_type_hint(
275     sema: &Semantics<RootDatabase>,
276     bind_pat: &ast::IdentPat,
277     pat_ty: &hir::Type,
278 ) -> bool {
279     let db = sema.db;
280
281     if pat_ty.is_unknown() {
282         return true;
283     }
284
285     if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() {
286         if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() {
287             return true;
288         }
289     }
290
291     for node in bind_pat.syntax().ancestors() {
292         match_ast! {
293             match node {
294                 ast::LetStmt(it) => return it.ty().is_some(),
295                 ast::Param(it) => return it.ty().is_some(),
296                 ast::MatchArm(_it) => return pat_is_enum_variant(db, bind_pat, pat_ty),
297                 ast::IfExpr(it) => {
298                     return it.condition().and_then(|condition| condition.pat()).is_some()
299                         && pat_is_enum_variant(db, bind_pat, pat_ty);
300                 },
301                 ast::WhileExpr(it) => {
302                     return it.condition().and_then(|condition| condition.pat()).is_some()
303                         && pat_is_enum_variant(db, bind_pat, pat_ty);
304                 },
305                 ast::ForExpr(it) => {
306                     // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
307                     // Type of expr should be iterable.
308                     return it.in_token().is_none() ||
309                         it.iterable()
310                             .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
311                             .map(TypeInfo::original)
312                             .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
313                 },
314                 _ => (),
315             }
316         }
317     }
318     false
319 }
320
321 fn should_hide_param_name_hint(
322     sema: &Semantics<RootDatabase>,
323     callable: &hir::Callable,
324     param_name: &str,
325     argument: &ast::Expr,
326 ) -> bool {
327     // These are to be tested in the `parameter_hint_heuristics` test
328     // hide when:
329     // - the parameter name is a suffix of the function's name
330     // - the argument is an enum whose name is equal to the parameter
331     // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
332     //   of argument with _ splitting it off
333     // - param starts with `ra_fixture`
334     // - param is a well known name in an unary function
335
336     let param_name = param_name.trim_start_matches('_');
337     if param_name.is_empty() {
338         return true;
339     }
340
341     let fn_name = match callable.kind() {
342         hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()),
343         _ => None,
344     };
345     let fn_name = fn_name.as_deref();
346     is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
347         || is_enum_name_similar_to_param_name(sema, argument, param_name)
348         || is_argument_similar_to_param_name(argument, param_name)
349         || param_name.starts_with("ra_fixture")
350         || (callable.n_params() == 1 && is_obvious_param(param_name))
351 }
352
353 fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
354     // check whether param_name and argument are the same or
355     // whether param_name is a prefix/suffix of argument(split at `_`)
356     let argument = match get_string_representation(argument) {
357         Some(argument) => argument,
358         None => return false,
359     };
360
361     let param_name = param_name.trim_start_matches('_');
362     let argument = argument.trim_start_matches('_');
363     if argument.strip_prefix(param_name).map_or(false, |s| s.starts_with('_')) {
364         return true;
365     }
366     if argument.strip_suffix(param_name).map_or(false, |s| s.ends_with('_')) {
367         return true;
368     }
369     argument == param_name
370 }
371
372 /// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal.
373 ///
374 /// `fn strip_suffix(suffix)` will be hidden.
375 /// `fn stripsuffix(suffix)` will not be hidden.
376 fn is_param_name_suffix_of_fn_name(
377     param_name: &str,
378     callable: &Callable,
379     fn_name: Option<&str>,
380 ) -> bool {
381     match (callable.n_params(), fn_name) {
382         (1, Some(function)) => {
383             function == param_name
384                 || (function.len() > param_name.len()
385                     && function.ends_with(param_name)
386                     && function[..function.len() - param_name.len()].ends_with('_'))
387         }
388         _ => false,
389     }
390 }
391
392 fn is_enum_name_similar_to_param_name(
393     sema: &Semantics<RootDatabase>,
394     argument: &ast::Expr,
395     param_name: &str,
396 ) -> bool {
397     match sema.type_of_expr(argument).and_then(|t| t.original.as_adt()) {
398         Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name,
399         _ => false,
400     }
401 }
402
403 fn get_string_representation(expr: &ast::Expr) -> Option<String> {
404     match expr {
405         ast::Expr::MethodCallExpr(method_call_expr) => {
406             let name_ref = method_call_expr.name_ref()?;
407             match name_ref.text().as_str() {
408                 "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
409                 name_ref => Some(name_ref.to_owned()),
410             }
411         }
412         ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
413         ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
414         ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
415         ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
416         _ => None,
417     }
418 }
419
420 fn is_obvious_param(param_name: &str) -> bool {
421     // avoid displaying hints for common functions like map, filter, etc.
422     // or other obvious words used in std
423     let is_obvious_param_name =
424         matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
425     param_name.len() == 1 || is_obvious_param_name
426 }
427
428 fn get_callable(
429     sema: &Semantics<RootDatabase>,
430     expr: &ast::Expr,
431 ) -> Option<(hir::Callable, ast::ArgList)> {
432     match expr {
433         ast::Expr::CallExpr(expr) => {
434             sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list())
435         }
436         ast::Expr::MethodCallExpr(expr) => {
437             sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())
438         }
439         _ => None,
440     }
441 }
442
443 #[cfg(test)]
444 mod tests {
445     use expect_test::{expect, Expect};
446     use test_utils::extract_annotations;
447
448     use crate::{fixture, inlay_hints::InlayHintsConfig};
449
450     const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
451         type_hints: true,
452         parameter_hints: true,
453         chaining_hints: true,
454         max_length: None,
455     };
456
457     fn check(ra_fixture: &str) {
458         check_with_config(TEST_CONFIG, ra_fixture);
459     }
460
461     fn check_params(ra_fixture: &str) {
462         check_with_config(
463             InlayHintsConfig {
464                 parameter_hints: true,
465                 type_hints: false,
466                 chaining_hints: false,
467                 max_length: None,
468             },
469             ra_fixture,
470         );
471     }
472
473     fn check_types(ra_fixture: &str) {
474         check_with_config(
475             InlayHintsConfig {
476                 parameter_hints: false,
477                 type_hints: true,
478                 chaining_hints: false,
479                 max_length: None,
480             },
481             ra_fixture,
482         );
483     }
484
485     fn check_chains(ra_fixture: &str) {
486         check_with_config(
487             InlayHintsConfig {
488                 parameter_hints: false,
489                 type_hints: false,
490                 chaining_hints: true,
491                 max_length: None,
492             },
493             ra_fixture,
494         );
495     }
496
497     fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
498         let (analysis, file_id) = fixture::file(&ra_fixture);
499         let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
500         let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
501         let actual =
502             inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
503         assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
504     }
505
506     fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
507         let (analysis, file_id) = fixture::file(&ra_fixture);
508         let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
509         expect.assert_debug_eq(&inlay_hints)
510     }
511
512     #[test]
513     fn hints_disabled() {
514         check_with_config(
515             InlayHintsConfig {
516                 type_hints: false,
517                 parameter_hints: false,
518                 chaining_hints: false,
519                 max_length: None,
520             },
521             r#"
522 fn foo(a: i32, b: i32) -> i32 { a + b }
523 fn main() {
524     let _x = foo(4, 4);
525 }"#,
526         );
527     }
528
529     // Parameter hint tests
530
531     #[test]
532     fn param_hints_only() {
533         check_params(
534             r#"
535 fn foo(a: i32, b: i32) -> i32 { a + b }
536 fn main() {
537     let _x = foo(
538         4,
539       //^ a
540         4,
541       //^ b
542     );
543 }"#,
544         );
545     }
546
547     #[test]
548     fn param_name_similar_to_fn_name_still_hints() {
549         check_params(
550             r#"
551 fn max(x: i32, y: i32) -> i32 { x + y }
552 fn main() {
553     let _x = max(
554         4,
555       //^ x
556         4,
557       //^ y
558     );
559 }"#,
560         );
561     }
562
563     #[test]
564     fn param_name_similar_to_fn_name() {
565         check_params(
566             r#"
567 fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
568 fn main() {
569     let _x = param_with_underscore(
570         4,
571     );
572 }"#,
573         );
574         check_params(
575             r#"
576 fn param_with_underscore(underscore: i32) -> i32 { underscore }
577 fn main() {
578     let _x = param_with_underscore(
579         4,
580     );
581 }"#,
582         );
583     }
584
585     #[test]
586     fn param_name_same_as_fn_name() {
587         check_params(
588             r#"
589 fn foo(foo: i32) -> i32 { foo }
590 fn main() {
591     let _x = foo(
592         4,
593     );
594 }"#,
595         );
596     }
597
598     #[test]
599     fn never_hide_param_when_multiple_params() {
600         check_params(
601             r#"
602 fn foo(foo: i32, bar: i32) -> i32 { bar + baz }
603 fn main() {
604     let _x = foo(
605         4,
606       //^ foo
607         8,
608       //^ bar
609     );
610 }"#,
611         );
612     }
613
614     #[test]
615     fn param_hints_look_through_as_ref_and_clone() {
616         check_params(
617             r#"
618 fn foo(bar: i32, baz: f32) {}
619
620 fn main() {
621     let bar = 3;
622     let baz = &"baz";
623     let fez = 1.0;
624     foo(bar.clone(), bar.clone());
625                    //^^^^^^^^^^^ baz
626     foo(bar.as_ref(), bar.as_ref());
627                     //^^^^^^^^^^^^ baz
628 }
629 "#,
630         );
631     }
632
633     #[test]
634     fn self_param_hints() {
635         check_params(
636             r#"
637 struct Foo;
638
639 impl Foo {
640     fn foo(self: Self) {}
641     fn bar(self: &Self) {}
642 }
643
644 fn main() {
645     Foo::foo(Foo);
646            //^^^ self
647     Foo::bar(&Foo);
648            //^^^^ self
649 }
650 "#,
651         )
652     }
653
654     #[test]
655     fn param_name_hints_show_for_literals() {
656         check_params(
657             r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
658 fn main() {
659     test(
660         0xa_b,
661       //^^^^^ a
662         0xa_b,
663       //^^^^^ b
664     );
665 }"#,
666         )
667     }
668
669     #[test]
670     fn function_call_parameter_hint() {
671         check_params(
672             r#"
673 //- minicore: option
674 struct FileId {}
675 struct SmolStr {}
676
677 struct TextRange {}
678 struct SyntaxKind {}
679 struct NavigationTarget {}
680
681 struct Test {}
682
683 impl Test {
684     fn method(&self, mut param: i32) -> i32 { param * 2 }
685
686     fn from_syntax(
687         file_id: FileId,
688         name: SmolStr,
689         focus_range: Option<TextRange>,
690         full_range: TextRange,
691         kind: SyntaxKind,
692         docs: Option<String>,
693     ) -> NavigationTarget {
694         NavigationTarget {}
695     }
696 }
697
698 fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
699     foo + bar
700 }
701
702 fn main() {
703     let not_literal = 1;
704     let _: i32 = test_func(1,    2,      "hello", 3,  not_literal);
705                          //^ foo ^ bar   ^^^^^^^ msg  ^^^^^^^^^^^ last
706     let t: Test = Test {};
707     t.method(123);
708            //^^^ param
709     Test::method(&t,      3456);
710                //^^ self  ^^^^ param
711     Test::from_syntax(
712         FileId {},
713       //^^^^^^^^^ file_id
714         "impl".into(),
715       //^^^^^^^^^^^^^ name
716         None,
717       //^^^^ focus_range
718         TextRange {},
719       //^^^^^^^^^^^^ full_range
720         SyntaxKind {},
721       //^^^^^^^^^^^^^ kind
722         None,
723       //^^^^ docs
724     );
725 }"#,
726         );
727     }
728
729     #[test]
730     fn parameter_hint_heuristics() {
731         check_params(
732             r#"
733 fn check(ra_fixture_thing: &str) {}
734
735 fn map(f: i32) {}
736 fn filter(predicate: i32) {}
737
738 fn strip_suffix(suffix: &str) {}
739 fn stripsuffix(suffix: &str) {}
740 fn same(same: u32) {}
741 fn same2(_same2: u32) {}
742
743 fn enum_matches_param_name(completion_kind: CompletionKind) {}
744
745 fn foo(param: u32) {}
746 fn bar(param_eter: u32) {}
747
748 enum CompletionKind {
749     Keyword,
750 }
751
752 fn non_ident_pat((a, b): (u32, u32)) {}
753
754 fn main() {
755     check("");
756
757     map(0);
758     filter(0);
759
760     strip_suffix("");
761     stripsuffix("");
762               //^^ suffix
763     same(0);
764     same2(0);
765
766     enum_matches_param_name(CompletionKind::Keyword);
767
768     let param = 0;
769     foo(param);
770     let param_end = 0;
771     foo(param_end);
772     let start_param = 0;
773     foo(start_param);
774     let param2 = 0;
775     foo(param2);
776       //^^^^^^ param
777
778     let param_eter = 0;
779     bar(param_eter);
780     let param_eter_end = 0;
781     bar(param_eter_end);
782     let start_param_eter = 0;
783     bar(start_param_eter);
784     let param_eter2 = 0;
785     bar(param_eter2);
786       //^^^^^^^^^^^ param_eter
787
788     non_ident_pat((0, 0));
789 }"#,
790         );
791     }
792
793     // Type-Hint tests
794
795     #[test]
796     fn type_hints_only() {
797         check_types(
798             r#"
799 fn foo(a: i32, b: i32) -> i32 { a + b }
800 fn main() {
801     let _x = foo(4, 4);
802       //^^ i32
803 }"#,
804         );
805     }
806
807     #[test]
808     fn type_hints_bindings_after_at() {
809         check_types(
810             r#"
811 //- minicore: option
812 fn main() {
813     let ref foo @ bar @ ref mut baz = 0;
814           //^^^ &i32
815                 //^^^ i32
816                               //^^^ &mut i32
817     let [x @ ..] = [0];
818        //^ [i32; 1]
819     if let x @ Some(_) = Some(0) {}
820          //^ Option<i32>
821     let foo @ (bar, baz) = (3, 3);
822       //^^^ (i32, i32)
823              //^^^ i32
824                   //^^^ i32
825 }"#,
826         );
827     }
828
829     #[test]
830     fn default_generic_types_should_not_be_displayed() {
831         check(
832             r#"
833 struct Test<K, T = u8> { k: K, t: T }
834
835 fn main() {
836     let zz = Test { t: 23u8, k: 33 };
837       //^^ Test<i32>
838     let zz_ref = &zz;
839       //^^^^^^ &Test<i32>
840     let test = || zz;
841       //^^^^ || -> Test<i32>
842 }"#,
843         );
844     }
845
846     #[test]
847     fn shorten_iterators_in_associated_params() {
848         check_types(
849             r#"
850 //- minicore: iterators
851 use core::iter;
852
853 pub struct SomeIter<T> {}
854
855 impl<T> SomeIter<T> {
856     pub fn new() -> Self { SomeIter {} }
857     pub fn push(&mut self, t: T) {}
858 }
859
860 impl<T> Iterator for SomeIter<T> {
861     type Item = T;
862     fn next(&mut self) -> Option<Self::Item> {
863         None
864     }
865 }
866
867 fn main() {
868     let mut some_iter = SomeIter::new();
869           //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
870       some_iter.push(iter::repeat(2).take(2));
871     let iter_of_iters = some_iter.take(2);
872       //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
873 }
874 "#,
875         );
876     }
877
878     #[test]
879     fn infer_call_method_return_associated_types_with_generic() {
880         check_types(
881             r#"
882             pub trait Default {
883                 fn default() -> Self;
884             }
885             pub trait Foo {
886                 type Bar: Default;
887             }
888
889             pub fn quux<T: Foo>() -> T::Bar {
890                 let y = Default::default();
891                   //^ <T as Foo>::Bar
892
893                 y
894             }
895             "#,
896         );
897     }
898
899     #[test]
900     fn fn_hints() {
901         check_types(
902             r#"
903 //- minicore: fn, sized
904 fn foo() -> impl Fn() { loop {} }
905 fn foo1() -> impl Fn(f64) { loop {} }
906 fn foo2() -> impl Fn(f64, f64) { loop {} }
907 fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
908 fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
909 fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
910 fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
911 fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
912
913 fn main() {
914     let foo = foo();
915      // ^^^ impl Fn()
916     let foo = foo1();
917      // ^^^ impl Fn(f64)
918     let foo = foo2();
919      // ^^^ impl Fn(f64, f64)
920     let foo = foo3();
921      // ^^^ impl Fn(f64, f64) -> u32
922     let foo = foo4();
923      // ^^^ &dyn Fn(f64, f64) -> u32
924     let foo = foo5();
925      // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
926     let foo = foo6();
927      // ^^^ impl Fn(f64, f64) -> u32
928     let foo = foo7();
929      // ^^^ *const impl Fn(f64, f64) -> u32
930 }
931 "#,
932         )
933     }
934
935     #[test]
936     fn fn_hints_ptr_rpit_fn_parentheses() {
937         check_types(
938             r#"
939 //- minicore: fn, sized
940 trait Trait {}
941
942 fn foo1() -> *const impl Fn() { loop {} }
943 fn foo2() -> *const (impl Fn() + Sized) { loop {} }
944 fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
945 fn foo4() -> *const (impl Sized + Fn()) { loop {} }
946 fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
947 fn foo6() -> *const (impl Fn() + Trait) { loop {} }
948 fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
949 fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
950 fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
951 fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
952
953 fn main() {
954     let foo = foo1();
955     //  ^^^ *const impl Fn()
956     let foo = foo2();
957     //  ^^^ *const impl Fn()
958     let foo = foo3();
959     //  ^^^ *const (impl Fn() + ?Sized)
960     let foo = foo4();
961     //  ^^^ *const impl Fn()
962     let foo = foo5();
963     //  ^^^ *const (impl Fn() + ?Sized)
964     let foo = foo6();
965     //  ^^^ *const (impl Fn() + Trait)
966     let foo = foo7();
967     //  ^^^ *const (impl Fn() + Trait)
968     let foo = foo8();
969     //  ^^^ *const (impl Fn() + Trait + ?Sized)
970     let foo = foo9();
971     //  ^^^ *const (impl Fn() -> u8 + ?Sized)
972     let foo = foo10();
973     //  ^^^ *const impl Fn()
974 }
975 "#,
976         )
977     }
978
979     #[test]
980     fn unit_structs_have_no_type_hints() {
981         check_types(
982             r#"
983 //- minicore: result
984 struct SyntheticSyntax;
985
986 fn main() {
987     match Ok(()) {
988         Ok(_) => (),
989         Err(SyntheticSyntax) => (),
990     }
991 }"#,
992         );
993     }
994
995     #[test]
996     fn let_statement() {
997         check_types(
998             r#"
999 #[derive(PartialEq)]
1000 enum Option<T> { None, Some(T) }
1001
1002 #[derive(PartialEq)]
1003 struct Test { a: Option<u32>, b: u8 }
1004
1005 fn main() {
1006     struct InnerStruct {}
1007
1008     let test = 54;
1009       //^^^^ i32
1010     let test: i32 = 33;
1011     let mut test = 33;
1012           //^^^^ i32
1013     let _ = 22;
1014     let test = "test";
1015       //^^^^ &str
1016     let test = InnerStruct {};
1017       //^^^^ InnerStruct
1018
1019     let test = unresolved();
1020
1021     let test = (42, 'a');
1022       //^^^^ (i32, char)
1023     let (a,    (b,     (c,)) = (2, (3, (9.2,));
1024        //^ i32  ^ i32   ^ f64
1025     let &x = &92;
1026        //^ i32
1027 }"#,
1028         );
1029     }
1030
1031     #[test]
1032     fn if_expr() {
1033         check_types(
1034             r#"
1035 //- minicore: option
1036 struct Test { a: Option<u32>, b: u8 }
1037
1038 fn main() {
1039     let test = Some(Test { a: Some(3), b: 1 });
1040       //^^^^ Option<Test>
1041     if let None = &test {};
1042     if let test = &test {};
1043          //^^^^ &Option<Test>
1044     if let Some(test) = &test {};
1045               //^^^^ &Test
1046     if let Some(Test { a,             b }) = &test {};
1047                      //^ &Option<u32> ^ &u8
1048     if let Some(Test { a: x,             b: y }) = &test {};
1049                         //^ &Option<u32>    ^ &u8
1050     if let Some(Test { a: Some(x),  b: y }) = &test {};
1051                              //^ &u32  ^ &u8
1052     if let Some(Test { a: None,  b: y }) = &test {};
1053                                   //^ &u8
1054     if let Some(Test { b: y, .. }) = &test {};
1055                         //^ &u8
1056     if test == None {}
1057 }"#,
1058         );
1059     }
1060
1061     #[test]
1062     fn while_expr() {
1063         check_types(
1064             r#"
1065 //- minicore: option
1066 struct Test { a: Option<u32>, b: u8 }
1067
1068 fn main() {
1069     let test = Some(Test { a: Some(3), b: 1 });
1070       //^^^^ Option<Test>
1071     while let Some(Test { a: Some(x),  b: y }) = &test {};
1072                                 //^ &u32  ^ &u8
1073 }"#,
1074         );
1075     }
1076
1077     #[test]
1078     fn match_arm_list() {
1079         check_types(
1080             r#"
1081 //- minicore: option
1082 struct Test { a: Option<u32>, b: u8 }
1083
1084 fn main() {
1085     match Some(Test { a: Some(3), b: 1 }) {
1086         None => (),
1087         test => (),
1088       //^^^^ Option<Test>
1089         Some(Test { a: Some(x), b: y }) => (),
1090                           //^ u32  ^ u8
1091         _ => {}
1092     }
1093 }"#,
1094         );
1095     }
1096
1097     #[test]
1098     fn incomplete_for_no_hint() {
1099         check_types(
1100             r#"
1101 fn main() {
1102     let data = &[1i32, 2, 3];
1103       //^^^^ &[i32; 3]
1104     for i
1105 }"#,
1106         );
1107         check(
1108             r#"
1109 pub struct Vec<T> {}
1110
1111 impl<T> Vec<T> {
1112     pub fn new() -> Self { Vec {} }
1113     pub fn push(&mut self, t: T) {}
1114 }
1115
1116 impl<T> IntoIterator for Vec<T> {
1117     type Item=T;
1118 }
1119
1120 fn main() {
1121     let mut data = Vec::new();
1122           //^^^^ Vec<&str>
1123     data.push("foo");
1124     for i in
1125
1126     println!("Unit expr");
1127 }
1128 "#,
1129         );
1130     }
1131
1132     #[test]
1133     fn complete_for_hint() {
1134         check_types(
1135             r#"
1136 //- minicore: iterator
1137 pub struct Vec<T> {}
1138
1139 impl<T> Vec<T> {
1140     pub fn new() -> Self { Vec {} }
1141     pub fn push(&mut self, t: T) {}
1142 }
1143
1144 impl<T> IntoIterator for Vec<T> {
1145     type Item=T;
1146 }
1147
1148 fn main() {
1149     let mut data = Vec::new();
1150           //^^^^ Vec<&str>
1151     data.push("foo");
1152     for i in data {
1153       //^ &str
1154       let z = i;
1155         //^ &str
1156     }
1157 }
1158 "#,
1159         );
1160     }
1161
1162     #[test]
1163     fn multi_dyn_trait_bounds() {
1164         check_types(
1165             r#"
1166 pub struct Vec<T> {}
1167
1168 impl<T> Vec<T> {
1169     pub fn new() -> Self { Vec {} }
1170 }
1171
1172 pub struct Box<T> {}
1173
1174 trait Display {}
1175 trait Sync {}
1176
1177 fn main() {
1178     let _v = Vec::<Box<&(dyn Display + Sync)>>::new();
1179       //^^ Vec<Box<&(dyn Display + Sync)>>
1180     let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
1181       //^^ Vec<Box<*const (dyn Display + Sync)>>
1182     let _v = Vec::<Box<dyn Display + Sync>>::new();
1183       //^^ Vec<Box<dyn Display + Sync>>
1184 }
1185 "#,
1186         );
1187     }
1188
1189     #[test]
1190     fn shorten_iterator_hints() {
1191         check_types(
1192             r#"
1193 //- minicore: iterators
1194 use core::iter;
1195
1196 struct MyIter;
1197
1198 impl Iterator for MyIter {
1199     type Item = ();
1200     fn next(&mut self) -> Option<Self::Item> {
1201         None
1202     }
1203 }
1204
1205 fn main() {
1206     let _x = MyIter;
1207       //^^ MyIter
1208     let _x = iter::repeat(0);
1209       //^^ impl Iterator<Item = i32>
1210     fn generic<T: Clone>(t: T) {
1211         let _x = iter::repeat(t);
1212           //^^ impl Iterator<Item = T>
1213         let _chained = iter::repeat(t).take(10);
1214           //^^^^^^^^ impl Iterator<Item = T>
1215     }
1216 }
1217 "#,
1218         );
1219     }
1220
1221     #[test]
1222     fn closures() {
1223         check(
1224             r#"
1225 fn main() {
1226     let mut start = 0;
1227           //^^^^^ i32
1228     (0..2).for_each(|increment| { start += increment; });
1229                    //^^^^^^^^^ i32
1230
1231     let multiply =
1232       //^^^^^^^^ |…| -> i32
1233       | a,     b| a * b
1234       //^ i32  ^ i32
1235     ;
1236
1237     let _: i32 = multiply(1, 2);
1238     let multiply_ref = &multiply;
1239       //^^^^^^^^^^^^ &|…| -> i32
1240
1241     let return_42 = || 42;
1242       //^^^^^^^^^ || -> i32
1243 }"#,
1244         );
1245     }
1246
1247     #[test]
1248     fn hint_truncation() {
1249         check_with_config(
1250             InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
1251             r#"
1252 struct Smol<T>(T);
1253
1254 struct VeryLongOuterName<T>(T);
1255
1256 fn main() {
1257     let a = Smol(0u32);
1258       //^ Smol<u32>
1259     let b = VeryLongOuterName(0usize);
1260       //^ VeryLongOuterName<…>
1261     let c = Smol(Smol(0u32))
1262       //^ Smol<Smol<…>>
1263 }"#,
1264         );
1265     }
1266
1267     // Chaining hint tests
1268
1269     #[test]
1270     fn chaining_hints_ignore_comments() {
1271         check_expect(
1272             InlayHintsConfig {
1273                 parameter_hints: false,
1274                 type_hints: false,
1275                 chaining_hints: true,
1276                 max_length: None,
1277             },
1278             r#"
1279 struct A(B);
1280 impl A { fn into_b(self) -> B { self.0 } }
1281 struct B(C);
1282 impl B { fn into_c(self) -> C { self.0 } }
1283 struct C;
1284
1285 fn main() {
1286     let c = A(B(C))
1287         .into_b() // This is a comment
1288         // This is another comment
1289         .into_c();
1290 }
1291 "#,
1292             expect![[r#"
1293                 [
1294                     InlayHint {
1295                         range: 147..172,
1296                         kind: ChainingHint,
1297                         label: "B",
1298                     },
1299                     InlayHint {
1300                         range: 147..154,
1301                         kind: ChainingHint,
1302                         label: "A",
1303                     },
1304                 ]
1305             "#]],
1306         );
1307     }
1308
1309     #[test]
1310     fn chaining_hints_without_newlines() {
1311         check_chains(
1312             r#"
1313 struct A(B);
1314 impl A { fn into_b(self) -> B { self.0 } }
1315 struct B(C);
1316 impl B { fn into_c(self) -> C { self.0 } }
1317 struct C;
1318
1319 fn main() {
1320     let c = A(B(C)).into_b().into_c();
1321 }"#,
1322         );
1323     }
1324
1325     #[test]
1326     fn struct_access_chaining_hints() {
1327         check_expect(
1328             InlayHintsConfig {
1329                 parameter_hints: false,
1330                 type_hints: false,
1331                 chaining_hints: true,
1332                 max_length: None,
1333             },
1334             r#"
1335 struct A { pub b: B }
1336 struct B { pub c: C }
1337 struct C(pub bool);
1338 struct D;
1339
1340 impl D {
1341     fn foo(&self) -> i32 { 42 }
1342 }
1343
1344 fn main() {
1345     let x = A { b: B { c: C(true) } }
1346         .b
1347         .c
1348         .0;
1349     let x = D
1350         .foo();
1351 }"#,
1352             expect![[r#"
1353                 [
1354                     InlayHint {
1355                         range: 143..190,
1356                         kind: ChainingHint,
1357                         label: "C",
1358                     },
1359                     InlayHint {
1360                         range: 143..179,
1361                         kind: ChainingHint,
1362                         label: "B",
1363                     },
1364                 ]
1365             "#]],
1366         );
1367     }
1368
1369     #[test]
1370     fn generic_chaining_hints() {
1371         check_expect(
1372             InlayHintsConfig {
1373                 parameter_hints: false,
1374                 type_hints: false,
1375                 chaining_hints: true,
1376                 max_length: None,
1377             },
1378             r#"
1379 struct A<T>(T);
1380 struct B<T>(T);
1381 struct C<T>(T);
1382 struct X<T,R>(T, R);
1383
1384 impl<T> A<T> {
1385     fn new(t: T) -> Self { A(t) }
1386     fn into_b(self) -> B<T> { B(self.0) }
1387 }
1388 impl<T> B<T> {
1389     fn into_c(self) -> C<T> { C(self.0) }
1390 }
1391 fn main() {
1392     let c = A::new(X(42, true))
1393         .into_b()
1394         .into_c();
1395 }
1396 "#,
1397             expect![[r#"
1398                 [
1399                     InlayHint {
1400                         range: 246..283,
1401                         kind: ChainingHint,
1402                         label: "B<X<i32, bool>>",
1403                     },
1404                     InlayHint {
1405                         range: 246..265,
1406                         kind: ChainingHint,
1407                         label: "A<X<i32, bool>>",
1408                     },
1409                 ]
1410             "#]],
1411         );
1412     }
1413
1414     #[test]
1415     fn shorten_iterator_chaining_hints() {
1416         check_expect(
1417             InlayHintsConfig {
1418                 parameter_hints: false,
1419                 type_hints: false,
1420                 chaining_hints: true,
1421                 max_length: None,
1422             },
1423             r#"
1424 //- minicore: iterators
1425 use core::iter;
1426
1427 struct MyIter;
1428
1429 impl Iterator for MyIter {
1430     type Item = ();
1431     fn next(&mut self) -> Option<Self::Item> {
1432         None
1433     }
1434 }
1435
1436 fn main() {
1437     let _x = MyIter.by_ref()
1438         .take(5)
1439         .by_ref()
1440         .take(5)
1441         .by_ref();
1442 }
1443 "#,
1444             expect![[r#"
1445                 [
1446                     InlayHint {
1447                         range: 174..241,
1448                         kind: ChainingHint,
1449                         label: "impl Iterator<Item = ()>",
1450                     },
1451                     InlayHint {
1452                         range: 174..224,
1453                         kind: ChainingHint,
1454                         label: "impl Iterator<Item = ()>",
1455                     },
1456                     InlayHint {
1457                         range: 174..206,
1458                         kind: ChainingHint,
1459                         label: "impl Iterator<Item = ()>",
1460                     },
1461                     InlayHint {
1462                         range: 174..189,
1463                         kind: ChainingHint,
1464                         label: "&mut MyIter",
1465                     },
1466                 ]
1467             "#]],
1468         );
1469     }
1470 }