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