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