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