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