]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/inlay_hints.rs
Trigger hover requests on closing brace hints
[rust.git] / crates / ide / src / inlay_hints.rs
1 use either::Either;
2 use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
3 use ide_db::{
4     base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
5     RootDatabase,
6 };
7 use itertools::Itertools;
8 use stdx::to_lower_snake_case;
9 use syntax::{
10     ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
11     match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
12     TextSize, T,
13 };
14
15 use crate::FileId;
16
17 #[derive(Clone, Debug, PartialEq, Eq)]
18 pub struct InlayHintsConfig {
19     pub render_colons: bool,
20     pub type_hints: bool,
21     pub parameter_hints: bool,
22     pub chaining_hints: bool,
23     pub reborrow_hints: ReborrowHints,
24     pub closure_return_type_hints: bool,
25     pub binding_mode_hints: bool,
26     pub lifetime_elision_hints: LifetimeElisionHints,
27     pub param_names_for_lifetime_elision_hints: bool,
28     pub hide_named_constructor_hints: bool,
29     pub max_length: Option<usize>,
30     pub closing_brace_hints_min_lines: Option<usize>,
31 }
32
33 #[derive(Clone, Debug, PartialEq, Eq)]
34 pub enum LifetimeElisionHints {
35     Always,
36     SkipTrivial,
37     Never,
38 }
39
40 #[derive(Clone, Debug, PartialEq, Eq)]
41 pub enum ReborrowHints {
42     Always,
43     MutableOnly,
44     Never,
45 }
46
47 #[derive(Clone, Debug, PartialEq, Eq)]
48 pub enum InlayKind {
49     BindingModeHint,
50     ChainingHint,
51     ClosingBraceHint(Option<TextSize>),
52     ClosureReturnTypeHint,
53     GenericParamListHint,
54     ImplicitReborrowHint,
55     LifetimeHint,
56     ParameterHint,
57     TypeHint,
58 }
59
60 #[derive(Debug)]
61 pub struct InlayHint {
62     pub range: TextRange,
63     pub kind: InlayKind,
64     pub label: String,
65 }
66
67 // Feature: Inlay Hints
68 //
69 // rust-analyzer shows additional information inline with the source code.
70 // Editors usually render this using read-only virtual text snippets interspersed with code.
71 //
72 // rust-analyzer by default shows hints for
73 //
74 // * types of local variables
75 // * names of function arguments
76 // * types of chained expressions
77 //
78 // Optionally, one can enable additional hints for
79 //
80 // * return types of closure expressions with blocks
81 // * elided lifetimes
82 // * compiler inserted reborrows
83 //
84 // |===
85 // | Editor  | Action Name
86 //
87 // | VS Code | **Rust Analyzer: Toggle inlay hints*
88 // |===
89 //
90 // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
91 pub(crate) fn inlay_hints(
92     db: &RootDatabase,
93     file_id: FileId,
94     range_limit: Option<FileRange>,
95     config: &InlayHintsConfig,
96 ) -> Vec<InlayHint> {
97     let _p = profile::span("inlay_hints");
98     let sema = Semantics::new(db);
99     let file = sema.parse(file_id);
100     let file = file.syntax();
101
102     let mut acc = Vec::new();
103
104     let hints = |node| hints(&mut acc, &sema, config, node);
105     match range_limit {
106         Some(FileRange { range, .. }) => match file.covering_element(range) {
107             NodeOrToken::Token(_) => return acc,
108             NodeOrToken::Node(n) => n
109                 .descendants()
110                 .filter(|descendant| range.intersect(descendant.text_range()).is_some())
111                 .for_each(hints),
112         },
113         None => file.descendants().for_each(hints),
114     };
115
116     acc
117 }
118
119 fn hints(
120     hints: &mut Vec<InlayHint>,
121     sema: &Semantics<RootDatabase>,
122     config: &InlayHintsConfig,
123     node: SyntaxNode,
124 ) {
125     let famous_defs = match sema.scope(&node) {
126         Some(it) => FamousDefs(sema, it.krate()),
127         None => return,
128     };
129
130     closing_brace_hints(hints, sema, config, node.clone());
131     match_ast! {
132         match node {
133             ast::Expr(expr) => {
134                 chaining_hints(hints, sema, &famous_defs, config, &expr);
135                 match expr {
136                     ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
137                     ast::Expr::MethodCallExpr(it) => {
138                         param_name_hints(hints, sema, config, ast::Expr::from(it))
139                     }
140                     ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, it),
141                     // We could show reborrows for all expressions, but usually that is just noise to the user
142                     // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
143                     ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
144                     _ => None,
145                 }
146             },
147             ast::Pat(it) => {
148                 binding_mode_hints(hints, sema, config, &it);
149                 if let ast::Pat::IdentPat(it) = it {
150                     bind_pat_hints(hints, sema, config, &it);
151                 }
152                 Some(())
153             },
154             ast::Fn(it) => lifetime_fn_hints(hints, config, it),
155             _ => Some(()),
156         }
157     };
158 }
159
160 fn closing_brace_hints(
161     acc: &mut Vec<InlayHint>,
162     sema: &Semantics<RootDatabase>,
163     config: &InlayHintsConfig,
164     node: SyntaxNode,
165 ) -> Option<()> {
166     let min_lines = config.closing_brace_hints_min_lines?;
167
168     let name = |it: ast::Name| it.syntax().text_range().start();
169
170     let mut closing_token;
171     let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
172         closing_token = item_list.r_curly_token()?;
173
174         let parent = item_list.syntax().parent()?;
175         match_ast! {
176             match parent {
177                 ast::Impl(imp) => {
178                     let imp = sema.to_def(&imp)?;
179                     let ty = imp.self_ty(sema.db);
180                     let trait_ = imp.trait_(sema.db);
181
182                     (match trait_ {
183                         Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
184                         None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
185                     }, None)
186                 },
187                 ast::Trait(tr) => {
188                     (format!("trait {}", tr.name()?), tr.name().map(name))
189                 },
190                 _ => return None,
191             }
192         }
193     } else if let Some(list) = ast::ItemList::cast(node.clone()) {
194         closing_token = list.r_curly_token()?;
195
196         let module = ast::Module::cast(list.syntax().parent()?)?;
197         (format!("mod {}", module.name()?), module.name().map(name))
198     } else if let Some(block) = ast::BlockExpr::cast(node.clone()) {
199         closing_token = block.stmt_list()?.r_curly_token()?;
200
201         let parent = block.syntax().parent()?;
202         match_ast! {
203             match parent {
204                 ast::Fn(it) => {
205                     // FIXME: this could include parameters, but `HirDisplay` prints too much info
206                     // and doesn't respect the max length either, so the hints end up way too long
207                     (format!("fn {}", it.name()?), it.name().map(name))
208                 },
209                 ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
210                 ast::Const(it) => {
211                     if it.underscore_token().is_some() {
212                         ("const _".into(), None)
213                     } else {
214                         (format!("const {}", it.name()?), it.name().map(name))
215                     }
216                 },
217                 _ => return None,
218             }
219         }
220     } else if let Some(mac) = ast::MacroCall::cast(node.clone()) {
221         let last_token = mac.syntax().last_token()?;
222         if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY {
223             return None;
224         }
225         closing_token = last_token;
226
227         (
228             format!("{}!", mac.path()?),
229             mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
230         )
231     } else {
232         return None;
233     };
234
235     if let Some(mut next) = closing_token.next_token() {
236         if next.kind() == T![;] {
237             if let Some(tok) = next.next_token() {
238                 closing_token = next;
239                 next = tok;
240             }
241         }
242         if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) {
243             // Only display the hint if the `}` is the last token on the line
244             return None;
245         }
246     }
247
248     let mut lines = 1;
249     node.text().for_each_chunk(|s| lines += s.matches('\n').count());
250     if lines < min_lines {
251         return None;
252     }
253
254     acc.push(InlayHint {
255         range: closing_token.text_range(),
256         kind: InlayKind::ClosingBraceHint(name_offset),
257         label,
258     });
259
260     None
261 }
262
263 fn lifetime_fn_hints(
264     acc: &mut Vec<InlayHint>,
265     config: &InlayHintsConfig,
266     func: ast::Fn,
267 ) -> Option<()> {
268     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
269         return None;
270     }
271
272     let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
273         range: t.text_range(),
274         kind: InlayKind::LifetimeHint,
275         label,
276     };
277
278     let param_list = func.param_list()?;
279     let generic_param_list = func.generic_param_list();
280     let ret_type = func.ret_type();
281     let self_param = param_list.self_param().filter(|it| it.amp_token().is_some());
282
283     let is_elided = |lt: &Option<ast::Lifetime>| match lt {
284         Some(lt) => matches!(lt.text().as_str(), "'_"),
285         None => true,
286     };
287
288     let potential_lt_refs = {
289         let mut acc: Vec<_> = vec![];
290         if let Some(self_param) = &self_param {
291             let lifetime = self_param.lifetime();
292             let is_elided = is_elided(&lifetime);
293             acc.push((None, self_param.amp_token(), lifetime, is_elided));
294         }
295         param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| {
296             // FIXME: check path types
297             walk_ty(&ty, &mut |ty| match ty {
298                 ast::Type::RefType(r) => {
299                     let lifetime = r.lifetime();
300                     let is_elided = is_elided(&lifetime);
301                     acc.push((
302                         pat.as_ref().and_then(|it| match it {
303                             ast::Pat::IdentPat(p) => p.name(),
304                             _ => None,
305                         }),
306                         r.amp_token(),
307                         lifetime,
308                         is_elided,
309                     ))
310                 }
311                 _ => (),
312             })
313         });
314         acc
315     };
316
317     // allocate names
318     let mut gen_idx_name = {
319         let mut gen = (0u8..).map(|idx| match idx {
320             idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
321             idx => format!("'{idx}").into(),
322         });
323         move || gen.next().unwrap_or_default()
324     };
325     let mut allocated_lifetimes = vec![];
326
327     let mut used_names: FxHashMap<SmolStr, usize> =
328         match config.param_names_for_lifetime_elision_hints {
329             true => generic_param_list
330                 .iter()
331                 .flat_map(|gpl| gpl.lifetime_params())
332                 .filter_map(|param| param.lifetime())
333                 .filter_map(|lt| Some((SmolStr::from(lt.text().as_str().get(1..)?), 0)))
334                 .collect(),
335             false => Default::default(),
336         };
337     {
338         let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided);
339         if let Some(_) = &self_param {
340             if let Some(_) = potential_lt_refs.next() {
341                 allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
342                     // self can't be used as a lifetime, so no need to check for collisions
343                     "'self".into()
344                 } else {
345                     gen_idx_name()
346                 });
347             }
348         }
349         potential_lt_refs.for_each(|(name, ..)| {
350             let name = match name {
351                 Some(it) if config.param_names_for_lifetime_elision_hints => {
352                     if let Some(c) = used_names.get_mut(it.text().as_str()) {
353                         *c += 1;
354                         SmolStr::from(format!("'{text}{c}", text = it.text().as_str()))
355                     } else {
356                         used_names.insert(it.text().as_str().into(), 0);
357                         SmolStr::from_iter(["\'", it.text().as_str()])
358                     }
359                 }
360                 _ => gen_idx_name(),
361             };
362             allocated_lifetimes.push(name);
363         });
364     }
365
366     // fetch output lifetime if elision rule applies
367     let output = match potential_lt_refs.as_slice() {
368         [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => {
369             match lifetime {
370                 Some(lt) => match lt.text().as_str() {
371                     "'_" => allocated_lifetimes.get(0).cloned(),
372                     "'static" => None,
373                     name => Some(name.into()),
374                 },
375                 None => allocated_lifetimes.get(0).cloned(),
376             }
377         }
378         [..] => None,
379     };
380
381     if allocated_lifetimes.is_empty() && output.is_none() {
382         return None;
383     }
384
385     // apply hints
386     // apply output if required
387     let mut is_trivial = true;
388     if let (Some(output_lt), Some(r)) = (&output, ret_type) {
389         if let Some(ty) = r.ty() {
390             walk_ty(&ty, &mut |ty| match ty {
391                 ast::Type::RefType(ty) if ty.lifetime().is_none() => {
392                     if let Some(amp) = ty.amp_token() {
393                         is_trivial = false;
394                         acc.push(mk_lt_hint(amp, output_lt.to_string()));
395                     }
396                 }
397                 _ => (),
398             })
399         }
400     }
401
402     if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial {
403         return None;
404     }
405
406     let mut a = allocated_lifetimes.iter();
407     for (_, amp_token, _, is_elided) in potential_lt_refs {
408         if is_elided {
409             let t = amp_token?;
410             let lt = a.next()?;
411             acc.push(mk_lt_hint(t, lt.to_string()));
412         }
413     }
414
415     // generate generic param list things
416     match (generic_param_list, allocated_lifetimes.as_slice()) {
417         (_, []) => (),
418         (Some(gpl), allocated_lifetimes) => {
419             let angle_tok = gpl.l_angle_token()?;
420             let is_empty = gpl.generic_params().next().is_none();
421             acc.push(mk_lt_hint(
422                 angle_tok,
423                 format!(
424                     "{}{}",
425                     allocated_lifetimes.iter().format(", "),
426                     if is_empty { "" } else { ", " }
427                 ),
428             ));
429         }
430         (None, allocated_lifetimes) => acc.push(InlayHint {
431             range: func.name()?.syntax().text_range(),
432             kind: InlayKind::GenericParamListHint,
433             label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
434         }),
435     }
436     Some(())
437 }
438
439 fn closure_ret_hints(
440     acc: &mut Vec<InlayHint>,
441     sema: &Semantics<RootDatabase>,
442     famous_defs: &FamousDefs,
443     config: &InlayHintsConfig,
444     closure: ast::ClosureExpr,
445 ) -> Option<()> {
446     if !config.closure_return_type_hints {
447         return None;
448     }
449
450     let param_list = match closure.body() {
451         Some(ast::Expr::BlockExpr(_)) => closure.param_list()?,
452         _ => return None,
453     };
454
455     let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
456     let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
457     let callable = ty.as_callable(sema.db)?;
458     let ty = callable.return_type();
459     if ty.is_unit() {
460         return None;
461     }
462     acc.push(InlayHint {
463         range: param_list.syntax().text_range(),
464         kind: InlayKind::ClosureReturnTypeHint,
465         label: hint_iterator(sema, &famous_defs, config, &ty)
466             .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()),
467     });
468     Some(())
469 }
470
471 fn reborrow_hints(
472     acc: &mut Vec<InlayHint>,
473     sema: &Semantics<RootDatabase>,
474     config: &InlayHintsConfig,
475     expr: &ast::Expr,
476 ) -> Option<()> {
477     if config.reborrow_hints == ReborrowHints::Never {
478         return None;
479     }
480
481     let descended = sema.descend_node_into_attributes(expr.clone()).pop();
482     let desc_expr = descended.as_ref().unwrap_or(expr);
483     let mutability = sema.is_implicit_reborrow(desc_expr)?;
484     let label = match mutability {
485         hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
486         hir::Mutability::Mut => "&mut *",
487         _ => return None,
488     };
489     acc.push(InlayHint {
490         range: expr.syntax().text_range(),
491         kind: InlayKind::ImplicitReborrowHint,
492         label: label.to_string(),
493     });
494     Some(())
495 }
496
497 fn chaining_hints(
498     acc: &mut Vec<InlayHint>,
499     sema: &Semantics<RootDatabase>,
500     famous_defs: &FamousDefs,
501     config: &InlayHintsConfig,
502     expr: &ast::Expr,
503 ) -> Option<()> {
504     if !config.chaining_hints {
505         return None;
506     }
507
508     if matches!(expr, ast::Expr::RecordExpr(_)) {
509         return None;
510     }
511
512     let descended = sema.descend_node_into_attributes(expr.clone()).pop();
513     let desc_expr = descended.as_ref().unwrap_or(expr);
514
515     let mut tokens = expr
516         .syntax()
517         .siblings_with_tokens(Direction::Next)
518         .filter_map(NodeOrToken::into_token)
519         .filter(|t| match t.kind() {
520             SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
521             SyntaxKind::COMMENT => false,
522             _ => true,
523         });
524
525     // Chaining can be defined as an expression whose next sibling tokens are newline and dot
526     // Ignoring extra whitespace and comments
527     let next = tokens.next()?.kind();
528     if next == SyntaxKind::WHITESPACE {
529         let mut next_next = tokens.next()?.kind();
530         while next_next == SyntaxKind::WHITESPACE {
531             next_next = tokens.next()?.kind();
532         }
533         if next_next == T![.] {
534             let ty = sema.type_of_expr(desc_expr)?.original;
535             if ty.is_unknown() {
536                 return None;
537             }
538             if matches!(expr, ast::Expr::PathExpr(_)) {
539                 if let Some(hir::Adt::Struct(st)) = ty.as_adt() {
540                     if st.fields(sema.db).is_empty() {
541                         return None;
542                     }
543                 }
544             }
545             acc.push(InlayHint {
546                 range: expr.syntax().text_range(),
547                 kind: InlayKind::ChainingHint,
548                 label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
549                     ty.display_truncated(sema.db, config.max_length).to_string()
550                 }),
551             });
552         }
553     }
554     Some(())
555 }
556
557 fn param_name_hints(
558     acc: &mut Vec<InlayHint>,
559     sema: &Semantics<RootDatabase>,
560     config: &InlayHintsConfig,
561     expr: ast::Expr,
562 ) -> Option<()> {
563     if !config.parameter_hints {
564         return None;
565     }
566
567     let (callable, arg_list) = get_callable(sema, &expr)?;
568     let hints = callable
569         .params(sema.db)
570         .into_iter()
571         .zip(arg_list.args())
572         .filter_map(|((param, _ty), arg)| {
573             // Only annotate hints for expressions that exist in the original file
574             let range = sema.original_range_opt(arg.syntax())?;
575             let param_name = match param? {
576                 Either::Left(_) => "self".to_string(),
577                 Either::Right(pat) => match pat {
578                     ast::Pat::IdentPat(it) => it.name()?.to_string(),
579                     _ => return None,
580                 },
581             };
582             Some((param_name, arg, range))
583         })
584         .filter(|(param_name, arg, _)| {
585             !should_hide_param_name_hint(sema, &callable, param_name, arg)
586         })
587         .map(|(param_name, _, FileRange { range, .. })| InlayHint {
588             range,
589             kind: InlayKind::ParameterHint,
590             label: param_name.into(),
591         });
592
593     acc.extend(hints);
594     Some(())
595 }
596
597 fn binding_mode_hints(
598     acc: &mut Vec<InlayHint>,
599     sema: &Semantics<RootDatabase>,
600     config: &InlayHintsConfig,
601     pat: &ast::Pat,
602 ) -> Option<()> {
603     if !config.binding_mode_hints {
604         return None;
605     }
606
607     let range = pat.syntax().text_range();
608     sema.pattern_adjustments(&pat).iter().for_each(|ty| {
609         let reference = ty.is_reference();
610         let mut_reference = ty.is_mutable_reference();
611         let r = match (reference, mut_reference) {
612             (true, true) => "&mut",
613             (true, false) => "&",
614             _ => return,
615         };
616         acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, label: r.to_string() });
617     });
618     match pat {
619         ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
620             let bm = sema.binding_mode_of_pat(pat)?;
621             let bm = match bm {
622                 hir::BindingMode::Move => return None,
623                 hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
624                 hir::BindingMode::Ref(Mutability::Shared) => "ref",
625             };
626             acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, label: bm.to_string() });
627         }
628         _ => (),
629     }
630
631     Some(())
632 }
633
634 fn bind_pat_hints(
635     acc: &mut Vec<InlayHint>,
636     sema: &Semantics<RootDatabase>,
637     config: &InlayHintsConfig,
638     pat: &ast::IdentPat,
639 ) -> Option<()> {
640     if !config.type_hints {
641         return None;
642     }
643
644     let descended = sema.descend_node_into_attributes(pat.clone()).pop();
645     let desc_pat = descended.as_ref().unwrap_or(pat);
646     let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
647
648     if should_not_display_type_hint(sema, pat, &ty) {
649         return None;
650     }
651
652     let krate = sema.scope(desc_pat.syntax())?.krate();
653     let famous_defs = FamousDefs(sema, krate);
654     let label = hint_iterator(sema, &famous_defs, config, &ty);
655
656     let label = match label {
657         Some(label) => label,
658         None => {
659             let ty_name = ty.display_truncated(sema.db, config.max_length).to_string();
660             if config.hide_named_constructor_hints
661                 && is_named_constructor(sema, pat, &ty_name).is_some()
662             {
663                 return None;
664             }
665             ty_name
666         }
667     };
668
669     acc.push(InlayHint {
670         range: match pat.name() {
671             Some(name) => name.syntax().text_range(),
672             None => pat.syntax().text_range(),
673         },
674         kind: InlayKind::TypeHint,
675         label,
676     });
677
678     Some(())
679 }
680
681 fn is_named_constructor(
682     sema: &Semantics<RootDatabase>,
683     pat: &ast::IdentPat,
684     ty_name: &str,
685 ) -> Option<()> {
686     let let_node = pat.syntax().parent()?;
687     let expr = match_ast! {
688         match let_node {
689             ast::LetStmt(it) => it.initializer(),
690             ast::LetExpr(it) => it.expr(),
691             _ => None,
692         }
693     }?;
694
695     let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
696     // unwrap postfix expressions
697     let expr = match expr {
698         ast::Expr::TryExpr(it) => it.expr(),
699         ast::Expr::AwaitExpr(it) => it.expr(),
700         expr => Some(expr),
701     }?;
702     let expr = match expr {
703         ast::Expr::CallExpr(call) => match call.expr()? {
704             ast::Expr::PathExpr(path) => path,
705             _ => return None,
706         },
707         ast::Expr::PathExpr(path) => path,
708         _ => return None,
709     };
710     let path = expr.path()?;
711
712     let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db);
713     let callable_kind = callable.map(|it| it.kind());
714     let qual_seg = match callable_kind {
715         Some(hir::CallableKind::Function(_) | hir::CallableKind::TupleEnumVariant(_)) => {
716             path.qualifier()?.segment()
717         }
718         _ => path.segment(),
719     }?;
720
721     let ctor_name = match qual_seg.kind()? {
722         ast::PathSegmentKind::Name(name_ref) => {
723             match qual_seg.generic_arg_list().map(|it| it.generic_args()) {
724                 Some(generics) => format!("{}<{}>", name_ref, generics.format(", ")),
725                 None => name_ref.to_string(),
726             }
727         }
728         ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(),
729         _ => return None,
730     };
731     (ctor_name == ty_name).then(|| ())
732 }
733
734 /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
735 fn hint_iterator(
736     sema: &Semantics<RootDatabase>,
737     famous_defs: &FamousDefs,
738     config: &InlayHintsConfig,
739     ty: &hir::Type,
740 ) -> Option<String> {
741     let db = sema.db;
742     let strukt = ty.strip_references().as_adt()?;
743     let krate = strukt.module(db).krate();
744     if krate != famous_defs.core()? {
745         return None;
746     }
747     let iter_trait = famous_defs.core_iter_Iterator()?;
748     let iter_mod = famous_defs.core_iter()?;
749
750     // Assert that this struct comes from `core::iter`.
751     if !(strukt.visibility(db) == hir::Visibility::Public
752         && strukt.module(db).path_to_root(db).contains(&iter_mod))
753     {
754         return None;
755     }
756
757     if ty.impls_trait(db, iter_trait, &[]) {
758         let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
759             hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
760             _ => None,
761         })?;
762         if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
763             const LABEL_START: &str = "impl Iterator<Item = ";
764             const LABEL_END: &str = ">";
765
766             let ty_display = hint_iterator(sema, famous_defs, config, &ty)
767                 .map(|assoc_type_impl| assoc_type_impl.to_string())
768                 .unwrap_or_else(|| {
769                     ty.display_truncated(
770                         db,
771                         config
772                             .max_length
773                             .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
774                     )
775                     .to_string()
776                 });
777             return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END));
778         }
779     }
780
781     None
782 }
783
784 fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool {
785     if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() {
786         let pat_text = bind_pat.to_string();
787         enum_data
788             .variants(db)
789             .into_iter()
790             .map(|variant| variant.name(db).to_smol_str())
791             .any(|enum_name| enum_name == pat_text)
792     } else {
793         false
794     }
795 }
796
797 fn should_not_display_type_hint(
798     sema: &Semantics<RootDatabase>,
799     bind_pat: &ast::IdentPat,
800     pat_ty: &hir::Type,
801 ) -> bool {
802     let db = sema.db;
803
804     if pat_ty.is_unknown() {
805         return true;
806     }
807
808     if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() {
809         if s.fields(db).is_empty() && s.name(db).to_smol_str() == bind_pat.to_string() {
810             return true;
811         }
812     }
813
814     for node in bind_pat.syntax().ancestors() {
815         match_ast! {
816             match node {
817                 ast::LetStmt(it) => return it.ty().is_some(),
818                 // FIXME: We might wanna show type hints in parameters for non-top level patterns as well
819                 ast::Param(it) => return it.ty().is_some(),
820                 ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
821                 ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
822                 ast::IfExpr(_) => return false,
823                 ast::WhileExpr(_) => return false,
824                 ast::ForExpr(it) => {
825                     // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
826                     // Type of expr should be iterable.
827                     return it.in_token().is_none() ||
828                         it.iterable()
829                             .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
830                             .map(TypeInfo::original)
831                             .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
832                 },
833                 _ => (),
834             }
835         }
836     }
837     false
838 }
839
840 fn should_hide_param_name_hint(
841     sema: &Semantics<RootDatabase>,
842     callable: &hir::Callable,
843     param_name: &str,
844     argument: &ast::Expr,
845 ) -> bool {
846     // These are to be tested in the `parameter_hint_heuristics` test
847     // hide when:
848     // - the parameter name is a suffix of the function's name
849     // - the argument is an enum whose name is equal to the parameter
850     // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
851     //   of argument with _ splitting it off
852     // - param starts with `ra_fixture`
853     // - param is a well known name in a unary function
854
855     let param_name = param_name.trim_start_matches('_');
856     if param_name.is_empty() {
857         return true;
858     }
859
860     if matches!(argument, ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(UnaryOp::Not)) {
861         return false;
862     }
863
864     let fn_name = match callable.kind() {
865         hir::CallableKind::Function(it) => Some(it.name(sema.db).to_smol_str()),
866         _ => None,
867     };
868     let fn_name = fn_name.as_deref();
869     is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
870         || is_enum_name_similar_to_param_name(sema, argument, param_name)
871         || is_argument_similar_to_param_name(argument, param_name)
872         || param_name.starts_with("ra_fixture")
873         || (callable.n_params() == 1 && is_obvious_param(param_name))
874 }
875
876 fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
877     // check whether param_name and argument are the same or
878     // whether param_name is a prefix/suffix of argument(split at `_`)
879     let argument = match get_string_representation(argument) {
880         Some(argument) => argument,
881         None => return false,
882     };
883
884     // std is honestly too panic happy...
885     let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at));
886
887     let param_name = param_name.trim_start_matches('_');
888     let argument = argument.trim_start_matches('_');
889
890     match str_split_at(argument, param_name.len()) {
891         Some((prefix, rest)) if prefix.eq_ignore_ascii_case(param_name) => {
892             return rest.is_empty() || rest.starts_with('_');
893         }
894         _ => (),
895     }
896     match argument.len().checked_sub(param_name.len()).and_then(|at| str_split_at(argument, at)) {
897         Some((rest, suffix)) if param_name.eq_ignore_ascii_case(suffix) => {
898             return rest.is_empty() || rest.ends_with('_');
899         }
900         _ => (),
901     }
902     false
903 }
904
905 /// Hide the parameter name of a unary function if it is a `_` - prefixed suffix of the function's name, or equal.
906 ///
907 /// `fn strip_suffix(suffix)` will be hidden.
908 /// `fn stripsuffix(suffix)` will not be hidden.
909 fn is_param_name_suffix_of_fn_name(
910     param_name: &str,
911     callable: &Callable,
912     fn_name: Option<&str>,
913 ) -> bool {
914     match (callable.n_params(), fn_name) {
915         (1, Some(function)) => {
916             function == param_name
917                 || function
918                     .len()
919                     .checked_sub(param_name.len())
920                     .and_then(|at| function.is_char_boundary(at).then(|| function.split_at(at)))
921                     .map_or(false, |(prefix, suffix)| {
922                         suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_')
923                     })
924         }
925         _ => false,
926     }
927 }
928
929 fn is_enum_name_similar_to_param_name(
930     sema: &Semantics<RootDatabase>,
931     argument: &ast::Expr,
932     param_name: &str,
933 ) -> bool {
934     match sema.type_of_expr(argument).and_then(|t| t.original.as_adt()) {
935         Some(hir::Adt::Enum(e)) => {
936             to_lower_snake_case(&e.name(sema.db).to_smol_str()) == param_name
937         }
938         _ => false,
939     }
940 }
941
942 fn get_string_representation(expr: &ast::Expr) -> Option<String> {
943     match expr {
944         ast::Expr::MethodCallExpr(method_call_expr) => {
945             let name_ref = method_call_expr.name_ref()?;
946             match name_ref.text().as_str() {
947                 "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
948                 name_ref => Some(name_ref.to_owned()),
949             }
950         }
951         ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
952         ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
953         ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
954         ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
955         ast::Expr::CastExpr(cast_expr) => get_string_representation(&cast_expr.expr()?),
956         _ => None,
957     }
958 }
959
960 fn is_obvious_param(param_name: &str) -> bool {
961     // avoid displaying hints for common functions like map, filter, etc.
962     // or other obvious words used in std
963     let is_obvious_param_name =
964         matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
965     param_name.len() == 1 || is_obvious_param_name
966 }
967
968 fn get_callable(
969     sema: &Semantics<RootDatabase>,
970     expr: &ast::Expr,
971 ) -> Option<(hir::Callable, ast::ArgList)> {
972     match expr {
973         ast::Expr::CallExpr(expr) => {
974             let descended = sema.descend_node_into_attributes(expr.clone()).pop();
975             let expr = descended.as_ref().unwrap_or(expr);
976             sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list())
977         }
978         ast::Expr::MethodCallExpr(expr) => {
979             let descended = sema.descend_node_into_attributes(expr.clone()).pop();
980             let expr = descended.as_ref().unwrap_or(expr);
981             sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())
982         }
983         _ => None,
984     }
985 }
986
987 #[cfg(test)]
988 mod tests {
989     use expect_test::{expect, Expect};
990     use ide_db::base_db::FileRange;
991     use itertools::Itertools;
992     use syntax::{TextRange, TextSize};
993     use test_utils::extract_annotations;
994
995     use crate::inlay_hints::ReborrowHints;
996     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
997
998     const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
999         render_colons: false,
1000         type_hints: false,
1001         parameter_hints: false,
1002         chaining_hints: false,
1003         lifetime_elision_hints: LifetimeElisionHints::Never,
1004         closure_return_type_hints: false,
1005         reborrow_hints: ReborrowHints::Always,
1006         binding_mode_hints: false,
1007         hide_named_constructor_hints: false,
1008         param_names_for_lifetime_elision_hints: false,
1009         max_length: None,
1010         closing_brace_hints_min_lines: None,
1011     };
1012     const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
1013         type_hints: true,
1014         parameter_hints: true,
1015         chaining_hints: true,
1016         reborrow_hints: ReborrowHints::Always,
1017         closure_return_type_hints: true,
1018         binding_mode_hints: true,
1019         lifetime_elision_hints: LifetimeElisionHints::Always,
1020         ..DISABLED_CONFIG
1021     };
1022
1023     #[track_caller]
1024     fn check(ra_fixture: &str) {
1025         check_with_config(TEST_CONFIG, ra_fixture);
1026     }
1027
1028     #[track_caller]
1029     fn check_params(ra_fixture: &str) {
1030         check_with_config(
1031             InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG },
1032             ra_fixture,
1033         );
1034     }
1035
1036     #[track_caller]
1037     fn check_types(ra_fixture: &str) {
1038         check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
1039     }
1040
1041     #[track_caller]
1042     fn check_chains(ra_fixture: &str) {
1043         check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture);
1044     }
1045
1046     #[track_caller]
1047     fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
1048         let (analysis, file_id) = fixture::file(ra_fixture);
1049         let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
1050         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
1051         let actual = inlay_hints
1052             .into_iter()
1053             .map(|it| (it.range, it.label.to_string()))
1054             .sorted_by_key(|(range, _)| range.start())
1055             .collect::<Vec<_>>();
1056         expected.sort_by_key(|(range, _)| range.start());
1057
1058         assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
1059     }
1060
1061     #[track_caller]
1062     fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
1063         let (analysis, file_id) = fixture::file(ra_fixture);
1064         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
1065         expect.assert_debug_eq(&inlay_hints)
1066     }
1067
1068     #[test]
1069     fn hints_disabled() {
1070         check_with_config(
1071             InlayHintsConfig { render_colons: true, ..DISABLED_CONFIG },
1072             r#"
1073 fn foo(a: i32, b: i32) -> i32 { a + b }
1074 fn main() {
1075     let _x = foo(4, 4);
1076 }"#,
1077         );
1078     }
1079
1080     // Parameter hint tests
1081
1082     #[test]
1083     fn param_hints_only() {
1084         check_params(
1085             r#"
1086 fn foo(a: i32, b: i32) -> i32 { a + b }
1087 fn main() {
1088     let _x = foo(
1089         4,
1090       //^ a
1091         4,
1092       //^ b
1093     );
1094 }"#,
1095         );
1096     }
1097
1098     #[test]
1099     fn param_name_similar_to_fn_name_still_hints() {
1100         check_params(
1101             r#"
1102 fn max(x: i32, y: i32) -> i32 { x + y }
1103 fn main() {
1104     let _x = max(
1105         4,
1106       //^ x
1107         4,
1108       //^ y
1109     );
1110 }"#,
1111         );
1112     }
1113
1114     #[test]
1115     fn param_name_similar_to_fn_name() {
1116         check_params(
1117             r#"
1118 fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
1119 fn main() {
1120     let _x = param_with_underscore(
1121         4,
1122     );
1123 }"#,
1124         );
1125         check_params(
1126             r#"
1127 fn param_with_underscore(underscore: i32) -> i32 { underscore }
1128 fn main() {
1129     let _x = param_with_underscore(
1130         4,
1131     );
1132 }"#,
1133         );
1134     }
1135
1136     #[test]
1137     fn param_name_same_as_fn_name() {
1138         check_params(
1139             r#"
1140 fn foo(foo: i32) -> i32 { foo }
1141 fn main() {
1142     let _x = foo(
1143         4,
1144     );
1145 }"#,
1146         );
1147     }
1148
1149     #[test]
1150     fn never_hide_param_when_multiple_params() {
1151         check_params(
1152             r#"
1153 fn foo(foo: i32, bar: i32) -> i32 { bar + baz }
1154 fn main() {
1155     let _x = foo(
1156         4,
1157       //^ foo
1158         8,
1159       //^ bar
1160     );
1161 }"#,
1162         );
1163     }
1164
1165     #[test]
1166     fn param_hints_look_through_as_ref_and_clone() {
1167         check_params(
1168             r#"
1169 fn foo(bar: i32, baz: f32) {}
1170
1171 fn main() {
1172     let bar = 3;
1173     let baz = &"baz";
1174     let fez = 1.0;
1175     foo(bar.clone(), bar.clone());
1176                    //^^^^^^^^^^^ baz
1177     foo(bar.as_ref(), bar.as_ref());
1178                     //^^^^^^^^^^^^ baz
1179 }
1180 "#,
1181         );
1182     }
1183
1184     #[test]
1185     fn self_param_hints() {
1186         check_params(
1187             r#"
1188 struct Foo;
1189
1190 impl Foo {
1191     fn foo(self: Self) {}
1192     fn bar(self: &Self) {}
1193 }
1194
1195 fn main() {
1196     Foo::foo(Foo);
1197            //^^^ self
1198     Foo::bar(&Foo);
1199            //^^^^ self
1200 }
1201 "#,
1202         )
1203     }
1204
1205     #[test]
1206     fn param_name_hints_show_for_literals() {
1207         check_params(
1208             r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
1209 fn main() {
1210     test(
1211         0xa_b,
1212       //^^^^^ a
1213         0xa_b,
1214       //^^^^^ b
1215     );
1216 }"#,
1217         )
1218     }
1219
1220     #[test]
1221     fn function_call_parameter_hint() {
1222         check_params(
1223             r#"
1224 //- minicore: option
1225 struct FileId {}
1226 struct SmolStr {}
1227
1228 struct TextRange {}
1229 struct SyntaxKind {}
1230 struct NavigationTarget {}
1231
1232 struct Test {}
1233
1234 impl Test {
1235     fn method(&self, mut param: i32) -> i32 { param * 2 }
1236
1237     fn from_syntax(
1238         file_id: FileId,
1239         name: SmolStr,
1240         focus_range: Option<TextRange>,
1241         full_range: TextRange,
1242         kind: SyntaxKind,
1243         docs: Option<String>,
1244     ) -> NavigationTarget {
1245         NavigationTarget {}
1246     }
1247 }
1248
1249 fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
1250     foo + bar
1251 }
1252
1253 fn main() {
1254     let not_literal = 1;
1255     let _: i32 = test_func(1,    2,      "hello", 3,  not_literal);
1256                          //^ foo ^ bar   ^^^^^^^ msg  ^^^^^^^^^^^ last
1257     let t: Test = Test {};
1258     t.method(123);
1259            //^^^ param
1260     Test::method(&t,      3456);
1261                //^^ self  ^^^^ param
1262     Test::from_syntax(
1263         FileId {},
1264       //^^^^^^^^^ file_id
1265         "impl".into(),
1266       //^^^^^^^^^^^^^ name
1267         None,
1268       //^^^^ focus_range
1269         TextRange {},
1270       //^^^^^^^^^^^^ full_range
1271         SyntaxKind {},
1272       //^^^^^^^^^^^^^ kind
1273         None,
1274       //^^^^ docs
1275     );
1276 }"#,
1277         );
1278     }
1279
1280     #[test]
1281     fn parameter_hint_heuristics() {
1282         check_params(
1283             r#"
1284 fn check(ra_fixture_thing: &str) {}
1285
1286 fn map(f: i32) {}
1287 fn filter(predicate: i32) {}
1288
1289 fn strip_suffix(suffix: &str) {}
1290 fn stripsuffix(suffix: &str) {}
1291 fn same(same: u32) {}
1292 fn same2(_same2: u32) {}
1293
1294 fn enum_matches_param_name(completion_kind: CompletionKind) {}
1295
1296 fn foo(param: u32) {}
1297 fn bar(param_eter: u32) {}
1298
1299 enum CompletionKind {
1300     Keyword,
1301 }
1302
1303 fn non_ident_pat((a, b): (u32, u32)) {}
1304
1305 fn main() {
1306     const PARAM: u32 = 0;
1307     foo(PARAM);
1308     foo(!PARAM);
1309      // ^^^^^^ param
1310     check("");
1311
1312     map(0);
1313     filter(0);
1314
1315     strip_suffix("");
1316     stripsuffix("");
1317               //^^ suffix
1318     same(0);
1319     same2(0);
1320
1321     enum_matches_param_name(CompletionKind::Keyword);
1322
1323     let param = 0;
1324     foo(param);
1325     foo(param as _);
1326     let param_end = 0;
1327     foo(param_end);
1328     let start_param = 0;
1329     foo(start_param);
1330     let param2 = 0;
1331     foo(param2);
1332       //^^^^^^ param
1333
1334     let param_eter = 0;
1335     bar(param_eter);
1336     let param_eter_end = 0;
1337     bar(param_eter_end);
1338     let start_param_eter = 0;
1339     bar(start_param_eter);
1340     let param_eter2 = 0;
1341     bar(param_eter2);
1342       //^^^^^^^^^^^ param_eter
1343
1344     non_ident_pat((0, 0));
1345 }"#,
1346         );
1347     }
1348
1349     // Type-Hint tests
1350
1351     #[test]
1352     fn type_hints_only() {
1353         check_types(
1354             r#"
1355 fn foo(a: i32, b: i32) -> i32 { a + b }
1356 fn main() {
1357     let _x = foo(4, 4);
1358       //^^ i32
1359 }"#,
1360         );
1361     }
1362
1363     #[test]
1364     fn type_hints_bindings_after_at() {
1365         check_types(
1366             r#"
1367 //- minicore: option
1368 fn main() {
1369     let ref foo @ bar @ ref mut baz = 0;
1370           //^^^ &i32
1371                 //^^^ i32
1372                               //^^^ &mut i32
1373     let [x @ ..] = [0];
1374        //^ [i32; 1]
1375     if let x @ Some(_) = Some(0) {}
1376          //^ Option<i32>
1377     let foo @ (bar, baz) = (3, 3);
1378       //^^^ (i32, i32)
1379              //^^^ i32
1380                   //^^^ i32
1381 }"#,
1382         );
1383     }
1384
1385     #[test]
1386     fn default_generic_types_should_not_be_displayed() {
1387         check(
1388             r#"
1389 struct Test<K, T = u8> { k: K, t: T }
1390
1391 fn main() {
1392     let zz = Test { t: 23u8, k: 33 };
1393       //^^ Test<i32>
1394     let zz_ref = &zz;
1395       //^^^^^^ &Test<i32>
1396     let test = || zz;
1397       //^^^^ || -> Test<i32>
1398 }"#,
1399         );
1400     }
1401
1402     #[test]
1403     fn shorten_iterators_in_associated_params() {
1404         check_types(
1405             r#"
1406 //- minicore: iterators
1407 use core::iter;
1408
1409 pub struct SomeIter<T> {}
1410
1411 impl<T> SomeIter<T> {
1412     pub fn new() -> Self { SomeIter {} }
1413     pub fn push(&mut self, t: T) {}
1414 }
1415
1416 impl<T> Iterator for SomeIter<T> {
1417     type Item = T;
1418     fn next(&mut self) -> Option<Self::Item> {
1419         None
1420     }
1421 }
1422
1423 fn main() {
1424     let mut some_iter = SomeIter::new();
1425           //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
1426       some_iter.push(iter::repeat(2).take(2));
1427     let iter_of_iters = some_iter.take(2);
1428       //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
1429 }
1430 "#,
1431         );
1432     }
1433
1434     #[test]
1435     fn infer_call_method_return_associated_types_with_generic() {
1436         check_types(
1437             r#"
1438             pub trait Default {
1439                 fn default() -> Self;
1440             }
1441             pub trait Foo {
1442                 type Bar: Default;
1443             }
1444
1445             pub fn quux<T: Foo>() -> T::Bar {
1446                 let y = Default::default();
1447                   //^ <T as Foo>::Bar
1448
1449                 y
1450             }
1451             "#,
1452         );
1453     }
1454
1455     #[test]
1456     fn fn_hints() {
1457         check_types(
1458             r#"
1459 //- minicore: fn, sized
1460 fn foo() -> impl Fn() { loop {} }
1461 fn foo1() -> impl Fn(f64) { loop {} }
1462 fn foo2() -> impl Fn(f64, f64) { loop {} }
1463 fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1464 fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1465 fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1466 fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1467 fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1468
1469 fn main() {
1470     let foo = foo();
1471      // ^^^ impl Fn()
1472     let foo = foo1();
1473      // ^^^ impl Fn(f64)
1474     let foo = foo2();
1475      // ^^^ impl Fn(f64, f64)
1476     let foo = foo3();
1477      // ^^^ impl Fn(f64, f64) -> u32
1478     let foo = foo4();
1479      // ^^^ &dyn Fn(f64, f64) -> u32
1480     let foo = foo5();
1481      // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
1482     let foo = foo6();
1483      // ^^^ impl Fn(f64, f64) -> u32
1484     let foo = foo7();
1485      // ^^^ *const impl Fn(f64, f64) -> u32
1486 }
1487 "#,
1488         )
1489     }
1490
1491     #[test]
1492     fn check_hint_range_limit() {
1493         let fixture = r#"
1494         //- minicore: fn, sized
1495         fn foo() -> impl Fn() { loop {} }
1496         fn foo1() -> impl Fn(f64) { loop {} }
1497         fn foo2() -> impl Fn(f64, f64) { loop {} }
1498         fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1499         fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1500         fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1501         fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1502         fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1503
1504         fn main() {
1505             let foo = foo();
1506             let foo = foo1();
1507             let foo = foo2();
1508              // ^^^ impl Fn(f64, f64)
1509             let foo = foo3();
1510              // ^^^ impl Fn(f64, f64) -> u32
1511             let foo = foo4();
1512             let foo = foo5();
1513             let foo = foo6();
1514             let foo = foo7();
1515         }
1516         "#;
1517         let (analysis, file_id) = fixture::file(fixture);
1518         let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
1519         let inlay_hints = analysis
1520             .inlay_hints(
1521                 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
1522                 file_id,
1523                 Some(FileRange {
1524                     file_id,
1525                     range: TextRange::new(TextSize::from(500), TextSize::from(600)),
1526                 }),
1527             )
1528             .unwrap();
1529         let actual =
1530             inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
1531         assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
1532     }
1533
1534     #[test]
1535     fn fn_hints_ptr_rpit_fn_parentheses() {
1536         check_types(
1537             r#"
1538 //- minicore: fn, sized
1539 trait Trait {}
1540
1541 fn foo1() -> *const impl Fn() { loop {} }
1542 fn foo2() -> *const (impl Fn() + Sized) { loop {} }
1543 fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
1544 fn foo4() -> *const (impl Sized + Fn()) { loop {} }
1545 fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
1546 fn foo6() -> *const (impl Fn() + Trait) { loop {} }
1547 fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
1548 fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
1549 fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
1550 fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
1551
1552 fn main() {
1553     let foo = foo1();
1554     //  ^^^ *const impl Fn()
1555     let foo = foo2();
1556     //  ^^^ *const impl Fn()
1557     let foo = foo3();
1558     //  ^^^ *const (impl Fn() + ?Sized)
1559     let foo = foo4();
1560     //  ^^^ *const impl Fn()
1561     let foo = foo5();
1562     //  ^^^ *const (impl Fn() + ?Sized)
1563     let foo = foo6();
1564     //  ^^^ *const (impl Fn() + Trait)
1565     let foo = foo7();
1566     //  ^^^ *const (impl Fn() + Trait)
1567     let foo = foo8();
1568     //  ^^^ *const (impl Fn() + Trait + ?Sized)
1569     let foo = foo9();
1570     //  ^^^ *const (impl Fn() -> u8 + ?Sized)
1571     let foo = foo10();
1572     //  ^^^ *const impl Fn()
1573 }
1574 "#,
1575         )
1576     }
1577
1578     #[test]
1579     fn unit_structs_have_no_type_hints() {
1580         check_types(
1581             r#"
1582 //- minicore: result
1583 struct SyntheticSyntax;
1584
1585 fn main() {
1586     match Ok(()) {
1587         Ok(_) => (),
1588         Err(SyntheticSyntax) => (),
1589     }
1590 }"#,
1591         );
1592     }
1593
1594     #[test]
1595     fn let_statement() {
1596         check_types(
1597             r#"
1598 #[derive(PartialEq)]
1599 enum Option<T> { None, Some(T) }
1600
1601 #[derive(PartialEq)]
1602 struct Test { a: Option<u32>, b: u8 }
1603
1604 fn main() {
1605     struct InnerStruct {}
1606
1607     let test = 54;
1608       //^^^^ i32
1609     let test: i32 = 33;
1610     let mut test = 33;
1611           //^^^^ i32
1612     let _ = 22;
1613     let test = "test";
1614       //^^^^ &str
1615     let test = InnerStruct {};
1616       //^^^^ InnerStruct
1617
1618     let test = unresolved();
1619
1620     let test = (42, 'a');
1621       //^^^^ (i32, char)
1622     let (a,    (b,     (c,)) = (2, (3, (9.2,));
1623        //^ i32  ^ i32   ^ f64
1624     let &x = &92;
1625        //^ i32
1626 }"#,
1627         );
1628     }
1629
1630     #[test]
1631     fn if_expr() {
1632         check_types(
1633             r#"
1634 //- minicore: option
1635 struct Test { a: Option<u32>, b: u8 }
1636
1637 fn main() {
1638     let test = Some(Test { a: Some(3), b: 1 });
1639       //^^^^ Option<Test>
1640     if let None = &test {};
1641     if let test = &test {};
1642          //^^^^ &Option<Test>
1643     if let Some(test) = &test {};
1644               //^^^^ &Test
1645     if let Some(Test { a,             b }) = &test {};
1646                      //^ &Option<u32> ^ &u8
1647     if let Some(Test { a: x,             b: y }) = &test {};
1648                         //^ &Option<u32>    ^ &u8
1649     if let Some(Test { a: Some(x),  b: y }) = &test {};
1650                              //^ &u32  ^ &u8
1651     if let Some(Test { a: None,  b: y }) = &test {};
1652                                   //^ &u8
1653     if let Some(Test { b: y, .. }) = &test {};
1654                         //^ &u8
1655     if test == None {}
1656 }"#,
1657         );
1658     }
1659
1660     #[test]
1661     fn while_expr() {
1662         check_types(
1663             r#"
1664 //- minicore: option
1665 struct Test { a: Option<u32>, b: u8 }
1666
1667 fn main() {
1668     let test = Some(Test { a: Some(3), b: 1 });
1669       //^^^^ Option<Test>
1670     while let Some(Test { a: Some(x),  b: y }) = &test {};
1671                                 //^ &u32  ^ &u8
1672 }"#,
1673         );
1674     }
1675
1676     #[test]
1677     fn match_arm_list() {
1678         check_types(
1679             r#"
1680 //- minicore: option
1681 struct Test { a: Option<u32>, b: u8 }
1682
1683 fn main() {
1684     match Some(Test { a: Some(3), b: 1 }) {
1685         None => (),
1686         test => (),
1687       //^^^^ Option<Test>
1688         Some(Test { a: Some(x), b: y }) => (),
1689                           //^ u32  ^ u8
1690         _ => {}
1691     }
1692 }"#,
1693         );
1694     }
1695
1696     #[test]
1697     fn complete_for_hint() {
1698         check_types(
1699             r#"
1700 //- minicore: iterator
1701 pub struct Vec<T> {}
1702
1703 impl<T> Vec<T> {
1704     pub fn new() -> Self { Vec {} }
1705     pub fn push(&mut self, t: T) {}
1706 }
1707
1708 impl<T> IntoIterator for Vec<T> {
1709     type Item=T;
1710 }
1711
1712 fn main() {
1713     let mut data = Vec::new();
1714           //^^^^ Vec<&str>
1715     data.push("foo");
1716     for i in data {
1717       //^ &str
1718       let z = i;
1719         //^ &str
1720     }
1721 }
1722 "#,
1723         );
1724     }
1725
1726     #[test]
1727     fn multi_dyn_trait_bounds() {
1728         check_types(
1729             r#"
1730 pub struct Vec<T> {}
1731
1732 impl<T> Vec<T> {
1733     pub fn new() -> Self { Vec {} }
1734 }
1735
1736 pub struct Box<T> {}
1737
1738 trait Display {}
1739 trait Sync {}
1740
1741 fn main() {
1742     // The block expression wrapping disables the constructor hint hiding logic
1743     let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
1744       //^^ Vec<Box<&(dyn Display + Sync)>>
1745     let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
1746       //^^ Vec<Box<*const (dyn Display + Sync)>>
1747     let _v = { Vec::<Box<dyn Display + Sync>>::new() };
1748       //^^ Vec<Box<dyn Display + Sync>>
1749 }
1750 "#,
1751         );
1752     }
1753
1754     #[test]
1755     fn shorten_iterator_hints() {
1756         check_types(
1757             r#"
1758 //- minicore: iterators
1759 use core::iter;
1760
1761 struct MyIter;
1762
1763 impl Iterator for MyIter {
1764     type Item = ();
1765     fn next(&mut self) -> Option<Self::Item> {
1766         None
1767     }
1768 }
1769
1770 fn main() {
1771     let _x = MyIter;
1772       //^^ MyIter
1773     let _x = iter::repeat(0);
1774       //^^ impl Iterator<Item = i32>
1775     fn generic<T: Clone>(t: T) {
1776         let _x = iter::repeat(t);
1777           //^^ impl Iterator<Item = T>
1778         let _chained = iter::repeat(t).take(10);
1779           //^^^^^^^^ impl Iterator<Item = T>
1780     }
1781 }
1782 "#,
1783         );
1784     }
1785
1786     #[test]
1787     fn skip_constructor_and_enum_type_hints() {
1788         check_with_config(
1789             InlayHintsConfig {
1790                 type_hints: true,
1791                 hide_named_constructor_hints: true,
1792                 ..DISABLED_CONFIG
1793             },
1794             r#"
1795 //- minicore: try, option
1796 use core::ops::ControlFlow;
1797
1798 mod x {
1799     pub mod y { pub struct Foo; }
1800     pub struct Foo;
1801     pub enum AnotherEnum {
1802         Variant()
1803     };
1804 }
1805 struct Struct;
1806 struct TupleStruct();
1807
1808 impl Struct {
1809     fn new() -> Self {
1810         Struct
1811     }
1812     fn try_new() -> ControlFlow<(), Self> {
1813         ControlFlow::Continue(Struct)
1814     }
1815 }
1816
1817 struct Generic<T>(T);
1818 impl Generic<i32> {
1819     fn new() -> Self {
1820         Generic(0)
1821     }
1822 }
1823
1824 enum Enum {
1825     Variant(u32)
1826 }
1827
1828 fn times2(value: i32) -> i32 {
1829     2 * value
1830 }
1831
1832 fn main() {
1833     let enumb = Enum::Variant(0);
1834
1835     let strukt = x::Foo;
1836     let strukt = x::y::Foo;
1837     let strukt = Struct;
1838     let strukt = Struct::new();
1839
1840     let tuple_struct = TupleStruct();
1841
1842     let generic0 = Generic::new();
1843     //  ^^^^^^^^ Generic<i32>
1844     let generic1 = Generic(0);
1845     //  ^^^^^^^^ Generic<i32>
1846     let generic2 = Generic::<i32>::new();
1847     let generic3 = <Generic<i32>>::new();
1848     let generic4 = Generic::<i32>(0);
1849
1850
1851     let option = Some(0);
1852     //  ^^^^^^ Option<i32>
1853     let func = times2;
1854     //  ^^^^ fn times2(i32) -> i32
1855     let closure = |x: i32| x * 2;
1856     //  ^^^^^^^ |i32| -> i32
1857 }
1858
1859 fn fallible() -> ControlFlow<()> {
1860     let strukt = Struct::try_new()?;
1861 }
1862 "#,
1863         );
1864     }
1865
1866     #[test]
1867     fn shows_constructor_type_hints_when_enabled() {
1868         check_types(
1869             r#"
1870 //- minicore: try
1871 use core::ops::ControlFlow;
1872
1873 struct Struct;
1874 struct TupleStruct();
1875
1876 impl Struct {
1877     fn new() -> Self {
1878         Struct
1879     }
1880     fn try_new() -> ControlFlow<(), Self> {
1881         ControlFlow::Continue(Struct)
1882     }
1883 }
1884
1885 struct Generic<T>(T);
1886 impl Generic<i32> {
1887     fn new() -> Self {
1888         Generic(0)
1889     }
1890 }
1891
1892 fn main() {
1893     let strukt = Struct::new();
1894      // ^^^^^^ Struct
1895     let tuple_struct = TupleStruct();
1896      // ^^^^^^^^^^^^ TupleStruct
1897     let generic0 = Generic::new();
1898      // ^^^^^^^^ Generic<i32>
1899     let generic1 = Generic::<i32>::new();
1900      // ^^^^^^^^ Generic<i32>
1901     let generic2 = <Generic<i32>>::new();
1902      // ^^^^^^^^ Generic<i32>
1903 }
1904
1905 fn fallible() -> ControlFlow<()> {
1906     let strukt = Struct::try_new()?;
1907      // ^^^^^^ Struct
1908 }
1909 "#,
1910         );
1911     }
1912
1913     #[test]
1914     fn closures() {
1915         check(
1916             r#"
1917 fn main() {
1918     let mut start = 0;
1919           //^^^^^ i32
1920     (0..2).for_each(|increment      | { start += increment; });
1921                    //^^^^^^^^^ i32
1922
1923     let multiply =
1924       //^^^^^^^^ |i32, i32| -> i32
1925       | a,     b| a * b
1926       //^ i32  ^ i32
1927
1928     ;
1929
1930     let _: i32 = multiply(1, 2);
1931     let multiply_ref = &multiply;
1932       //^^^^^^^^^^^^ &|i32, i32| -> i32
1933
1934     let return_42 = || 42;
1935       //^^^^^^^^^ || -> i32
1936       || { 42 };
1937     //^^ i32
1938 }"#,
1939         );
1940     }
1941
1942     #[test]
1943     fn hint_truncation() {
1944         check_with_config(
1945             InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
1946             r#"
1947 struct Smol<T>(T);
1948
1949 struct VeryLongOuterName<T>(T);
1950
1951 fn main() {
1952     let a = Smol(0u32);
1953       //^ Smol<u32>
1954     let b = VeryLongOuterName(0usize);
1955       //^ VeryLongOuterName<…>
1956     let c = Smol(Smol(0u32))
1957       //^ Smol<Smol<…>>
1958 }"#,
1959         );
1960     }
1961
1962     // Chaining hint tests
1963
1964     #[test]
1965     fn chaining_hints_ignore_comments() {
1966         check_expect(
1967             InlayHintsConfig { type_hints: false, chaining_hints: true, ..DISABLED_CONFIG },
1968             r#"
1969 struct A(B);
1970 impl A { fn into_b(self) -> B { self.0 } }
1971 struct B(C);
1972 impl B { fn into_c(self) -> C { self.0 } }
1973 struct C;
1974
1975 fn main() {
1976     let c = A(B(C))
1977         .into_b() // This is a comment
1978         // This is another comment
1979         .into_c();
1980 }
1981 "#,
1982             expect![[r#"
1983                 [
1984                     InlayHint {
1985                         range: 147..172,
1986                         kind: ChainingHint,
1987                         label: "B",
1988                     },
1989                     InlayHint {
1990                         range: 147..154,
1991                         kind: ChainingHint,
1992                         label: "A",
1993                     },
1994                 ]
1995             "#]],
1996         );
1997     }
1998
1999     #[test]
2000     fn chaining_hints_without_newlines() {
2001         check_chains(
2002             r#"
2003 struct A(B);
2004 impl A { fn into_b(self) -> B { self.0 } }
2005 struct B(C);
2006 impl B { fn into_c(self) -> C { self.0 } }
2007 struct C;
2008
2009 fn main() {
2010     let c = A(B(C)).into_b().into_c();
2011 }"#,
2012         );
2013     }
2014
2015     #[test]
2016     fn struct_access_chaining_hints() {
2017         check_expect(
2018             InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
2019             r#"
2020 struct A { pub b: B }
2021 struct B { pub c: C }
2022 struct C(pub bool);
2023 struct D;
2024
2025 impl D {
2026     fn foo(&self) -> i32 { 42 }
2027 }
2028
2029 fn main() {
2030     let x = A { b: B { c: C(true) } }
2031         .b
2032         .c
2033         .0;
2034     let x = D
2035         .foo();
2036 }"#,
2037             expect![[r#"
2038                 [
2039                     InlayHint {
2040                         range: 143..190,
2041                         kind: ChainingHint,
2042                         label: "C",
2043                     },
2044                     InlayHint {
2045                         range: 143..179,
2046                         kind: ChainingHint,
2047                         label: "B",
2048                     },
2049                 ]
2050             "#]],
2051         );
2052     }
2053
2054     #[test]
2055     fn generic_chaining_hints() {
2056         check_expect(
2057             InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
2058             r#"
2059 struct A<T>(T);
2060 struct B<T>(T);
2061 struct C<T>(T);
2062 struct X<T,R>(T, R);
2063
2064 impl<T> A<T> {
2065     fn new(t: T) -> Self { A(t) }
2066     fn into_b(self) -> B<T> { B(self.0) }
2067 }
2068 impl<T> B<T> {
2069     fn into_c(self) -> C<T> { C(self.0) }
2070 }
2071 fn main() {
2072     let c = A::new(X(42, true))
2073         .into_b()
2074         .into_c();
2075 }
2076 "#,
2077             expect![[r#"
2078                 [
2079                     InlayHint {
2080                         range: 246..283,
2081                         kind: ChainingHint,
2082                         label: "B<X<i32, bool>>",
2083                     },
2084                     InlayHint {
2085                         range: 246..265,
2086                         kind: ChainingHint,
2087                         label: "A<X<i32, bool>>",
2088                     },
2089                 ]
2090             "#]],
2091         );
2092     }
2093
2094     #[test]
2095     fn shorten_iterator_chaining_hints() {
2096         check_expect(
2097             InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
2098             r#"
2099 //- minicore: iterators
2100 use core::iter;
2101
2102 struct MyIter;
2103
2104 impl Iterator for MyIter {
2105     type Item = ();
2106     fn next(&mut self) -> Option<Self::Item> {
2107         None
2108     }
2109 }
2110
2111 fn main() {
2112     let _x = MyIter.by_ref()
2113         .take(5)
2114         .by_ref()
2115         .take(5)
2116         .by_ref();
2117 }
2118 "#,
2119             expect![[r#"
2120                 [
2121                     InlayHint {
2122                         range: 174..241,
2123                         kind: ChainingHint,
2124                         label: "impl Iterator<Item = ()>",
2125                     },
2126                     InlayHint {
2127                         range: 174..224,
2128                         kind: ChainingHint,
2129                         label: "impl Iterator<Item = ()>",
2130                     },
2131                     InlayHint {
2132                         range: 174..206,
2133                         kind: ChainingHint,
2134                         label: "impl Iterator<Item = ()>",
2135                     },
2136                     InlayHint {
2137                         range: 174..189,
2138                         kind: ChainingHint,
2139                         label: "&mut MyIter",
2140                     },
2141                 ]
2142             "#]],
2143         );
2144     }
2145
2146     #[test]
2147     fn hints_in_attr_call() {
2148         check_expect(
2149             TEST_CONFIG,
2150             r#"
2151 //- proc_macros: identity, input_replace
2152 struct Struct;
2153 impl Struct {
2154     fn chain(self) -> Self {
2155         self
2156     }
2157 }
2158 #[proc_macros::identity]
2159 fn main() {
2160     let strukt = Struct;
2161     strukt
2162         .chain()
2163         .chain()
2164         .chain();
2165     Struct::chain(strukt);
2166 }
2167 "#,
2168             expect![[r#"
2169                 [
2170                     InlayHint {
2171                         range: 124..130,
2172                         kind: TypeHint,
2173                         label: "Struct",
2174                     },
2175                     InlayHint {
2176                         range: 145..185,
2177                         kind: ChainingHint,
2178                         label: "Struct",
2179                     },
2180                     InlayHint {
2181                         range: 145..168,
2182                         kind: ChainingHint,
2183                         label: "Struct",
2184                     },
2185                     InlayHint {
2186                         range: 222..228,
2187                         kind: ParameterHint,
2188                         label: "self",
2189                     },
2190                 ]
2191             "#]],
2192         );
2193     }
2194
2195     #[test]
2196     fn hints_lifetimes() {
2197         check(
2198             r#"
2199 fn empty() {}
2200
2201 fn no_gpl(a: &()) {}
2202  //^^^^^^<'0>
2203           // ^'0
2204 fn empty_gpl<>(a: &()) {}
2205       //    ^'0   ^'0
2206 fn partial<'b>(a: &(), b: &'b ()) {}
2207 //        ^'0, $  ^'0
2208 fn partial<'a>(a: &'a (), b: &()) {}
2209 //        ^'0, $             ^'0
2210
2211 fn single_ret(a: &()) -> &() {}
2212 // ^^^^^^^^^^<'0>
2213               // ^'0     ^'0
2214 fn full_mul(a: &(), b: &()) {}
2215 // ^^^^^^^^<'0, '1>
2216             // ^'0     ^'1
2217
2218 fn foo<'c>(a: &'c ()) -> &() {}
2219                       // ^'c
2220
2221 fn nested_in(a: &   &X< &()>) {}
2222 // ^^^^^^^^^<'0, '1, '2>
2223               //^'0 ^'1 ^'2
2224 fn nested_out(a: &()) -> &   &X< &()>{}
2225 // ^^^^^^^^^^<'0>
2226                //^'0     ^'0 ^'0 ^'0
2227
2228 impl () {
2229     fn foo(&self) {}
2230     // ^^^<'0>
2231         // ^'0
2232     fn foo(&self) -> &() {}
2233     // ^^^<'0>
2234         // ^'0       ^'0
2235     fn foo(&self, a: &()) -> &() {}
2236     // ^^^<'0, '1>
2237         // ^'0       ^'1     ^'0
2238 }
2239 "#,
2240         );
2241     }
2242
2243     #[test]
2244     fn hints_lifetimes_named() {
2245         check_with_config(
2246             InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
2247             r#"
2248 fn nested_in<'named>(named: &        &X<      &()>) {}
2249 //          ^'named1, 'named2, 'named3, $
2250                           //^'named1 ^'named2 ^'named3
2251 "#,
2252         );
2253     }
2254
2255     #[test]
2256     fn hints_lifetimes_trivial_skip() {
2257         check_with_config(
2258             InlayHintsConfig {
2259                 lifetime_elision_hints: LifetimeElisionHints::SkipTrivial,
2260                 ..TEST_CONFIG
2261             },
2262             r#"
2263 fn no_gpl(a: &()) {}
2264 fn empty_gpl<>(a: &()) {}
2265 fn partial<'b>(a: &(), b: &'b ()) {}
2266 fn partial<'a>(a: &'a (), b: &()) {}
2267
2268 fn single_ret(a: &()) -> &() {}
2269 // ^^^^^^^^^^<'0>
2270               // ^'0     ^'0
2271 fn full_mul(a: &(), b: &()) {}
2272
2273 fn foo<'c>(a: &'c ()) -> &() {}
2274                       // ^'c
2275
2276 fn nested_in(a: &   &X< &()>) {}
2277 fn nested_out(a: &()) -> &   &X< &()>{}
2278 // ^^^^^^^^^^<'0>
2279                //^'0     ^'0 ^'0 ^'0
2280
2281 impl () {
2282     fn foo(&self) {}
2283     fn foo(&self) -> &() {}
2284     // ^^^<'0>
2285         // ^'0       ^'0
2286     fn foo(&self, a: &()) -> &() {}
2287     // ^^^<'0, '1>
2288         // ^'0       ^'1     ^'0
2289 }
2290 "#,
2291         );
2292     }
2293
2294     #[test]
2295     fn hints_implicit_reborrow() {
2296         check_with_config(
2297             InlayHintsConfig {
2298                 reborrow_hints: ReborrowHints::Always,
2299                 parameter_hints: true,
2300                 ..DISABLED_CONFIG
2301             },
2302             r#"
2303 fn __() {
2304     let unique = &mut ();
2305     let r_mov = unique;
2306     let foo: &mut _ = unique;
2307                     //^^^^^^ &mut *
2308     ref_mut_id(unique);
2309              //^^^^^^ mut_ref
2310              //^^^^^^ &mut *
2311     let shared = ref_id(unique);
2312                       //^^^^^^ shared_ref
2313                       //^^^^^^ &*
2314     let mov = shared;
2315     let r_mov: &_ = shared;
2316     ref_id(shared);
2317          //^^^^^^ shared_ref
2318
2319     identity(unique);
2320     identity(shared);
2321 }
2322 fn identity<T>(t: T) -> T {
2323     t
2324 }
2325 fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
2326     mut_ref
2327   //^^^^^^^ &mut *
2328 }
2329 fn ref_id(shared_ref: &()) -> &() {
2330     shared_ref
2331 }
2332 "#,
2333         );
2334     }
2335
2336     #[test]
2337     fn hints_binding_modes() {
2338         check_with_config(
2339             InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
2340             r#"
2341 fn __(
2342     (x,): (u32,),
2343     (x,): &(u32,),
2344   //^^^^&
2345    //^ ref
2346     (x,): &mut (u32,)
2347   //^^^^&mut
2348    //^ ref mut
2349 ) {
2350     let (x,) = (0,);
2351     let (x,) = &(0,);
2352       //^^^^ &
2353        //^ ref
2354     let (x,) = &mut (0,);
2355       //^^^^ &mut
2356        //^ ref mut
2357     let &mut (x,) = &mut (0,);
2358     let (ref mut x,) = &mut (0,);
2359       //^^^^^^^^^^^^ &mut
2360     let &mut (ref mut x,) = &mut (0,);
2361     let (mut x,) = &mut (0,);
2362       //^^^^^^^^ &mut
2363     match (0,) {
2364         (x,) => ()
2365     }
2366     match &(0,) {
2367         (x,) => ()
2368       //^^^^ &
2369        //^ ref
2370     }
2371     match &mut (0,) {
2372         (x,) => ()
2373       //^^^^ &mut
2374        //^ ref mut
2375     }
2376 }"#,
2377         );
2378     }
2379
2380     #[test]
2381     fn hints_closing_brace() {
2382         check_with_config(
2383             InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
2384             r#"
2385 fn a() {}
2386
2387 fn f() {
2388 } // no hint unless `}` is the last token on the line
2389
2390 fn g() {
2391   }
2392 //^ fn g
2393
2394 fn h<T>(with: T, arguments: u8, ...) {
2395   }
2396 //^ fn h
2397
2398 trait Tr {
2399     fn f();
2400     fn g() {
2401     }
2402   //^ fn g
2403   }
2404 //^ trait Tr
2405 impl Tr for () {
2406   }
2407 //^ impl Tr for ()
2408 impl dyn Tr {
2409   }
2410 //^ impl dyn Tr
2411
2412 static S0: () = 0;
2413 static S1: () = {};
2414 static S2: () = {
2415  };
2416 //^ static S2
2417 const _: () = {
2418  };
2419 //^ const _
2420
2421 mod m {
2422   }
2423 //^ mod m
2424
2425 m! {}
2426 m!();
2427 m!(
2428  );
2429 //^ m!
2430
2431 m! {
2432   }
2433 //^ m!
2434
2435 fn f() {
2436     let v = vec![
2437     ];
2438   }
2439 //^ fn f
2440 "#,
2441         );
2442     }
2443 }