]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide / src / inlay_hints / adjustment.rs
CommitLineData
9c376795
FG
1//! Implementation of "adjustment" inlay hints:
2//! ```no_run
3//! let _: u32 = /* <never-to-any> */ loop {};
4//! let _: &u32 = /* &* */ &mut 0;
5//! ```
fe692bf9
FG
6use either::Either;
7use hir::{
8 Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
9 Semantics,
10};
9c376795
FG
11use ide_db::RootDatabase;
12
9ffffee4 13use stdx::never;
9c376795
FG
14use syntax::{
15 ast::{self, make, AstNode},
16 ted,
17};
18
9ffffee4 19use crate::{
fe692bf9
FG
20 AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
21 InlayHintsConfig, InlayKind, InlayTooltip,
9ffffee4 22};
9c376795
FG
23
24pub(super) fn hints(
25 acc: &mut Vec<InlayHint>,
26 sema: &Semantics<'_, RootDatabase>,
27 config: &InlayHintsConfig,
28 expr: &ast::Expr,
29) -> Option<()> {
30 if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
31 return None;
32 }
33
34 if config.adjustment_hints == AdjustmentHints::Never {
35 return None;
36 }
37
353b0b11
FG
38 // ParenExpr resolve to their contained expressions HIR so they will dupe these hints
39 if let ast::Expr::ParenExpr(_) = expr {
9c376795
FG
40 return None;
41 }
353b0b11
FG
42 if let ast::Expr::BlockExpr(b) = expr {
43 if !b.is_standalone() {
44 return None;
45 }
46 }
9c376795
FG
47
48 let descended = sema.descend_node_into_attributes(expr.clone()).pop();
49 let desc_expr = descended.as_ref().unwrap_or(expr);
50 let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
51
353b0b11
FG
52 if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
53 if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
54 &*adjustments
55 {
56 // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
57 if source == target {
58 return None;
59 }
60 }
61 }
62
9c376795
FG
63 let (postfix, needs_outer_parens, needs_inner_parens) =
64 mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
65
66 if needs_outer_parens {
fe692bf9
FG
67 acc.push(InlayHint::opening_paren_before(
68 InlayKind::Adjustment,
69 expr.syntax().text_range(),
70 ));
9c376795
FG
71 }
72
73 if postfix && needs_inner_parens {
fe692bf9
FG
74 acc.push(InlayHint::opening_paren_before(
75 InlayKind::Adjustment,
76 expr.syntax().text_range(),
77 ));
78 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
79 }
80
fe692bf9
FG
81 let mut iter = if postfix {
82 Either::Left(adjustments.into_iter())
9c376795 83 } else {
fe692bf9 84 Either::Right(adjustments.into_iter().rev())
9c376795 85 };
fe692bf9 86 let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
9c376795 87
9ffffee4
FG
88 for Adjustment { source, target, kind } in iter {
89 if source == target {
353b0b11 90 cov_mark::hit!(same_type_adjustment);
9c376795
FG
91 continue;
92 }
93
94 // FIXME: Add some nicer tooltips to each of these
9ffffee4 95 let (text, coercion) = match kind {
9c376795 96 Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
9ffffee4
FG
97 ("<never-to-any>", "never to any")
98 }
fe692bf9
FG
99 Adjust::Deref(None) => ("*", "dereference"),
100 Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => {
101 ("*", "`Deref` dereference")
102 }
103 Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => {
104 ("*", "`DerefMut` dereference")
105 }
9ffffee4
FG
106 Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"),
107 Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"),
108 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => {
109 ("&raw const ", "const pointer borrow")
110 }
111 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => {
112 ("&raw mut ", "mut pointer borrow")
9c376795 113 }
9c376795
FG
114 // some of these could be represented via `as` casts, but that's not too nice and
115 // handling everything as a prefix expr makes the `(` and `)` insertion easier
116 Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
117 match cast {
9ffffee4
FG
118 PointerCast::ReifyFnPointer => {
119 ("<fn-item-to-fn-pointer>", "fn item to fn pointer")
120 }
121 PointerCast::UnsafeFnPointer => (
122 "<safe-fn-pointer-to-unsafe-fn-pointer>",
123 "safe fn pointer to unsafe fn pointer",
124 ),
9c376795 125 PointerCast::ClosureFnPointer(Safety::Unsafe) => {
9ffffee4
FG
126 ("<closure-to-unsafe-fn-pointer>", "closure to unsafe fn pointer")
127 }
128 PointerCast::ClosureFnPointer(Safety::Safe) => {
129 ("<closure-to-fn-pointer>", "closure to fn pointer")
9c376795 130 }
9ffffee4
FG
131 PointerCast::MutToConstPointer => {
132 ("<mut-ptr-to-const-ptr>", "mut ptr to const ptr")
133 }
134 PointerCast::ArrayToPointer => ("<array-ptr-to-element-ptr>", ""),
135 PointerCast::Unsize => ("<unsize>", "unsize"),
9c376795
FG
136 }
137 }
138 _ => continue,
139 };
140 acc.push(InlayHint {
141 range: expr.syntax().text_range(),
fe692bf9
FG
142 pad_left: false,
143 pad_right: false,
144 position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
145 kind: InlayKind::Adjustment,
9ffffee4
FG
146 label: InlayHintLabel::simple(
147 if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
148 Some(InlayTooltip::Markdown(format!(
149 "`{}` → `{}` ({coercion} coercion)",
150 source.display(sema.db),
151 target.display(sema.db),
152 ))),
153 None,
154 ),
fe692bf9 155 text_edit: None,
9c376795
FG
156 });
157 }
158 if !postfix && needs_inner_parens {
fe692bf9
FG
159 acc.push(InlayHint::opening_paren_before(
160 InlayKind::Adjustment,
161 expr.syntax().text_range(),
162 ));
163 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
164 }
165 if needs_outer_parens {
fe692bf9 166 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
167 }
168 Some(())
169}
170
fe692bf9 171/// Returns whatever the hint should be postfix and if we need to add parentheses on the inside and/or outside of `expr`,
9c376795
FG
172/// if we are going to add (`postfix`) adjustments hints to it.
173fn mode_and_needs_parens_for_adjustment_hints(
174 expr: &ast::Expr,
175 mode: AdjustmentHintsMode,
176) -> (bool, bool, bool) {
177 use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
178
179 match mode {
180 Prefix | Postfix => {
181 let postfix = matches!(mode, Postfix);
182 let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix);
183 (postfix, inside, outside)
184 }
185 PreferPrefix | PreferPostfix => {
186 let prefer_postfix = matches!(mode, PreferPostfix);
187
188 let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false);
189 let prefix = (false, pre_inside, pre_outside);
190 let pre_count = pre_inside as u8 + pre_outside as u8;
191
192 let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true);
193 let postfix = (true, post_inside, post_outside);
194 let post_count = post_inside as u8 + post_outside as u8;
195
196 match pre_count.cmp(&post_count) {
197 Less => prefix,
198 Greater => postfix,
199 Equal if prefer_postfix => postfix,
200 Equal => prefix,
201 }
202 }
203 }
204}
205
fe692bf9 206/// Returns whatever we need to add parentheses on the inside and/or outside of `expr`,
9c376795
FG
207/// if we are going to add (`postfix`) adjustments hints to it.
208fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
209 // This is a very miserable pile of hacks...
210 //
211 // `Expr::needs_parens_in` requires that the expression is the child of the other expression,
212 // that is supposed to be its parent.
213 //
214 // But we want to check what would happen if we add `*`/`.*` to the inner expression.
215 // To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
216 // to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
fe692bf9 217 // where "expr" is the `expr` parameter, `*expr` is the edited `expr`,
9c376795
FG
218 // and "parent" is the parent of the original expression...
219 //
fe692bf9 220 // For this we utilize mutable trees, which is a HACK, but it works.
9c376795
FG
221 //
222 // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this*
223
224 // Make `&expr`/`expr?`
225 let dummy_expr = {
226 // `make::*` function go through a string, so they parse wrongly.
227 // for example `` make::expr_try(`|| a`) `` would result in a
228 // `|| (a?)` and not `(|| a)?`.
229 //
230 // Thus we need dummy parens to preserve the relationship we want.
231 // The parens are then simply ignored by the following code.
232 let dummy_paren = make::expr_paren(expr.clone());
233 if postfix {
234 make::expr_try(dummy_paren)
235 } else {
236 make::expr_ref(dummy_paren, false)
237 }
238 };
239
240 // Do the dark mutable tree magic.
241 // This essentially makes `dummy_expr` and `expr` switch places (families),
242 // so that `expr`'s parent is not `dummy_expr`'s parent.
243 let dummy_expr = dummy_expr.clone_for_update();
244 let expr = expr.clone_for_update();
245 ted::replace(expr.syntax(), dummy_expr.syntax());
246
247 let parent = dummy_expr.syntax().parent();
9ffffee4
FG
248 let Some(expr) = (|| {
249 if postfix {
250 let ast::Expr::TryExpr(e) = &dummy_expr else { return None };
251 let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
9c376795 252
9ffffee4
FG
253 e.expr()
254 } else {
255 let ast::Expr::RefExpr(e) = &dummy_expr else { return None };
256 let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
9c376795 257
9ffffee4
FG
258 e.expr()
259 }
260 })() else {
261 never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr);
262 return (true, true)
9c376795
FG
263 };
264
265 // At this point
fe692bf9 266 // - `parent` is the parent of the original expression
9c376795
FG
267 // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
268 // - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
269
270 let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p));
271 let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone());
272
273 (needs_outer_parens, needs_inner_parens)
274}
275
276#[cfg(test)]
277mod tests {
278 use crate::{
279 inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
280 AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
281 };
282
283 #[test]
284 fn adjustment_hints() {
285 check_with_config(
286 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
287 r#"
fe692bf9 288//- minicore: coerce_unsized, fn, eq, index
9c376795
FG
289fn main() {
290 let _: u32 = loop {};
291 //^^^^^^^<never-to-any>
292 let _: &u32 = &mut 0;
293 //^^^^^^&
294 //^^^^^^*
295 let _: &mut u32 = &mut 0;
296 //^^^^^^&mut $
297 //^^^^^^*
298 let _: *const u32 = &mut 0;
299 //^^^^^^&raw const $
300 //^^^^^^*
301 let _: *mut u32 = &mut 0;
302 //^^^^^^&raw mut $
303 //^^^^^^*
304 let _: fn() = main;
305 //^^^^<fn-item-to-fn-pointer>
306 let _: unsafe fn() = main;
307 //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
308 //^^^^<fn-item-to-fn-pointer>
309 let _: unsafe fn() = main as fn();
310 //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
311 //^^^^^^^^^^^^(
312 //^^^^^^^^^^^^)
313 let _: fn() = || {};
314 //^^^^^<closure-to-fn-pointer>
315 let _: unsafe fn() = || {};
316 //^^^^^<closure-to-unsafe-fn-pointer>
317 let _: *const u32 = &mut 0u32 as *mut u32;
318 //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
319 //^^^^^^^^^^^^^^^^^^^^^(
320 //^^^^^^^^^^^^^^^^^^^^^)
321 let _: &mut [_] = &mut [0; 0];
322 //^^^^^^^^^^^<unsize>
323 //^^^^^^^^^^^&mut $
324 //^^^^^^^^^^^*
325
326 Struct.consume();
327 Struct.by_ref();
328 //^^^^^^(
329 //^^^^^^&
330 //^^^^^^)
331 Struct.by_ref_mut();
332 //^^^^^^(
333 //^^^^^^&mut $
334 //^^^^^^)
335
336 (&Struct).consume();
337 //^^^^^^^*
338 (&Struct).by_ref();
fe692bf9
FG
339 //^^^^^^^&
340 //^^^^^^^*
9c376795
FG
341
342 (&mut Struct).consume();
343 //^^^^^^^^^^^*
344 (&mut Struct).by_ref();
345 //^^^^^^^^^^^&
346 //^^^^^^^^^^^*
347 (&mut Struct).by_ref_mut();
fe692bf9
FG
348 //^^^^^^^^^^^&mut $
349 //^^^^^^^^^^^*
9c376795
FG
350
351 // Check that block-like expressions don't duplicate hints
352 let _: &mut [u32] = (&mut []);
353 //^^^^^^^<unsize>
354 //^^^^^^^&mut $
355 //^^^^^^^*
356 let _: &mut [u32] = { &mut [] };
357 //^^^^^^^<unsize>
358 //^^^^^^^&mut $
359 //^^^^^^^*
360 let _: &mut [u32] = unsafe { &mut [] };
361 //^^^^^^^<unsize>
362 //^^^^^^^&mut $
363 //^^^^^^^*
364 let _: &mut [u32] = if true {
365 &mut []
366 //^^^^^^^<unsize>
367 //^^^^^^^&mut $
368 //^^^^^^^*
369 } else {
370 loop {}
371 //^^^^^^^<never-to-any>
372 };
353b0b11 373 let _: &mut [u32] = match () { () => &mut [] };
9c376795
FG
374 //^^^^^^^<unsize>
375 //^^^^^^^&mut $
376 //^^^^^^^*
377
378 let _: &mut dyn Fn() = &mut || ();
379 //^^^^^^^^^^<unsize>
380 //^^^^^^^^^^&mut $
381 //^^^^^^^^^^*
353b0b11
FG
382 () == ();
383 // ^^&
384 // ^^&
385 (()) == {()};
386 // ^^&
387 // ^^^^&
fe692bf9
FG
388 let closure: dyn Fn = || ();
389 closure();
390 //^^^^^^^(
391 //^^^^^^^&
392 //^^^^^^^)
393 Struct[0];
394 //^^^^^^(
395 //^^^^^^&
396 //^^^^^^)
397 &mut Struct[0];
398 //^^^^^^(
399 //^^^^^^&mut $
400 //^^^^^^)
9c376795
FG
401}
402
403#[derive(Copy, Clone)]
404struct Struct;
405impl Struct {
406 fn consume(self) {}
407 fn by_ref(&self) {}
408 fn by_ref_mut(&mut self) {}
409}
fe692bf9
FG
410struct StructMut;
411impl core::ops::Index<usize> for Struct {
412 type Output = ();
413}
414impl core::ops::IndexMut for Struct {}
9c376795 415"#,
fe692bf9 416 );
9c376795
FG
417 }
418
419 #[test]
420 fn adjustment_hints_postfix() {
421 check_with_config(
422 InlayHintsConfig {
423 adjustment_hints: AdjustmentHints::Always,
424 adjustment_hints_mode: AdjustmentHintsMode::Postfix,
425 ..DISABLED_CONFIG
426 },
427 r#"
fe692bf9 428//- minicore: coerce_unsized, fn, eq, index
9c376795
FG
429fn main() {
430
431 Struct.consume();
432 Struct.by_ref();
433 //^^^^^^.&
434 Struct.by_ref_mut();
435 //^^^^^^.&mut
436
437 (&Struct).consume();
438 //^^^^^^^(
439 //^^^^^^^)
440 //^^^^^^^.*
441 (&Struct).by_ref();
fe692bf9
FG
442 //^^^^^^^(
443 //^^^^^^^)
444 //^^^^^^^.*
445 //^^^^^^^.&
9c376795
FG
446
447 (&mut Struct).consume();
448 //^^^^^^^^^^^(
449 //^^^^^^^^^^^)
450 //^^^^^^^^^^^.*
451 (&mut Struct).by_ref();
452 //^^^^^^^^^^^(
453 //^^^^^^^^^^^)
454 //^^^^^^^^^^^.*
455 //^^^^^^^^^^^.&
456 (&mut Struct).by_ref_mut();
fe692bf9
FG
457 //^^^^^^^^^^^(
458 //^^^^^^^^^^^)
459 //^^^^^^^^^^^.*
460 //^^^^^^^^^^^.&mut
9c376795
FG
461
462 // Check that block-like expressions don't duplicate hints
463 let _: &mut [u32] = (&mut []);
464 //^^^^^^^(
465 //^^^^^^^)
466 //^^^^^^^.*
467 //^^^^^^^.&mut
468 //^^^^^^^.<unsize>
469 let _: &mut [u32] = { &mut [] };
470 //^^^^^^^(
471 //^^^^^^^)
472 //^^^^^^^.*
473 //^^^^^^^.&mut
474 //^^^^^^^.<unsize>
475 let _: &mut [u32] = unsafe { &mut [] };
476 //^^^^^^^(
477 //^^^^^^^)
478 //^^^^^^^.*
479 //^^^^^^^.&mut
480 //^^^^^^^.<unsize>
481 let _: &mut [u32] = if true {
482 &mut []
483 //^^^^^^^(
484 //^^^^^^^)
485 //^^^^^^^.*
486 //^^^^^^^.&mut
487 //^^^^^^^.<unsize>
488 } else {
489 loop {}
490 //^^^^^^^.<never-to-any>
491 };
353b0b11 492 let _: &mut [u32] = match () { () => &mut [] };
9c376795
FG
493 //^^^^^^^(
494 //^^^^^^^)
495 //^^^^^^^.*
496 //^^^^^^^.&mut
497 //^^^^^^^.<unsize>
498
499 let _: &mut dyn Fn() = &mut || ();
500 //^^^^^^^^^^(
501 //^^^^^^^^^^)
502 //^^^^^^^^^^.*
503 //^^^^^^^^^^.&mut
504 //^^^^^^^^^^.<unsize>
353b0b11
FG
505 () == ();
506 // ^^.&
507 // ^^.&
508 (()) == {()};
509 // ^^.&
510 // ^^^^.&
fe692bf9
FG
511 let closure: dyn Fn = || ();
512 closure();
513 //^^^^^^^.&
514 Struct[0];
515 //^^^^^^.&
516 &mut Struct[0];
517 //^^^^^^.&mut
9c376795
FG
518}
519
520#[derive(Copy, Clone)]
521struct Struct;
522impl Struct {
523 fn consume(self) {}
524 fn by_ref(&self) {}
525 fn by_ref_mut(&mut self) {}
526}
fe692bf9
FG
527struct StructMut;
528impl core::ops::Index<usize> for Struct {
529 type Output = ();
530}
531impl core::ops::IndexMut for Struct {}
9c376795
FG
532"#,
533 );
534 }
535
536 #[test]
537 fn adjustment_hints_prefer_prefix() {
538 check_with_config(
539 InlayHintsConfig {
540 adjustment_hints: AdjustmentHints::Always,
541 adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix,
542 ..DISABLED_CONFIG
543 },
544 r#"
545fn main() {
546 let _: u32 = loop {};
547 //^^^^^^^<never-to-any>
548
549 Struct.by_ref();
550 //^^^^^^.&
551
552 let (): () = return ();
553 //^^^^^^^^^<never-to-any>
554
555 struct Struct;
556 impl Struct { fn by_ref(&self) {} }
557}
558 "#,
559 )
560 }
561
562 #[test]
563 fn adjustment_hints_prefer_postfix() {
564 check_with_config(
565 InlayHintsConfig {
566 adjustment_hints: AdjustmentHints::Always,
567 adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix,
568 ..DISABLED_CONFIG
569 },
570 r#"
571fn main() {
572 let _: u32 = loop {};
573 //^^^^^^^.<never-to-any>
574
575 Struct.by_ref();
576 //^^^^^^.&
577
578 let (): () = return ();
579 //^^^^^^^^^<never-to-any>
580
581 struct Struct;
582 impl Struct { fn by_ref(&self) {} }
583}
584 "#,
585 )
586 }
587
588 #[test]
589 fn never_to_never_is_never_shown() {
353b0b11 590 cov_mark::check!(same_type_adjustment);
9c376795
FG
591 check_with_config(
592 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
593 r#"
594fn never() -> ! {
595 return loop {};
596}
597
598fn or_else() {
599 let () = () else { return };
600}
601 "#,
602 )
603 }
604
605 #[test]
606 fn adjustment_hints_unsafe_only() {
607 check_with_config(
608 InlayHintsConfig {
609 adjustment_hints: AdjustmentHints::Always,
610 adjustment_hints_hide_outside_unsafe: true,
611 ..DISABLED_CONFIG
612 },
613 r#"
614unsafe fn enabled() {
615 f(&&());
616 //^^^^&
617 //^^^^*
618 //^^^^*
619}
620
621fn disabled() {
622 f(&&());
623}
624
625fn mixed() {
626 f(&&());
627
628 unsafe {
629 f(&&());
630 //^^^^&
631 //^^^^*
632 //^^^^*
633 }
634}
635
636const _: () = {
637 f(&&());
638
639 unsafe {
640 f(&&());
641 //^^^^&
642 //^^^^*
643 //^^^^*
644 }
645};
646
647static STATIC: () = {
648 f(&&());
649
650 unsafe {
651 f(&&());
652 //^^^^&
653 //^^^^*
654 //^^^^*
655 }
656};
657
658enum E {
659 Disable = { f(&&()); 0 },
660 Enable = unsafe { f(&&()); 1 },
661 //^^^^&
662 //^^^^*
663 //^^^^*
664}
665
666const fn f(_: &()) {}
667 "#,
668 )
669 }
670
671 #[test]
672 fn adjustment_hints_unsafe_only_with_item() {
673 check_with_config(
674 InlayHintsConfig {
675 adjustment_hints: AdjustmentHints::Always,
676 adjustment_hints_hide_outside_unsafe: true,
677 ..DISABLED_CONFIG
678 },
679 r#"
680fn a() {
681 struct Struct;
682 impl Struct {
683 fn by_ref(&self) {}
684 }
685
686 _ = Struct.by_ref();
687
688 _ = unsafe { Struct.by_ref() };
689 //^^^^^^(
690 //^^^^^^&
691 //^^^^^^)
692}
693 "#,
694 );
695 }
696
697 #[test]
353b0b11 698 fn let_stmt_explicit_ty() {
9c376795
FG
699 check_with_config(
700 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
701 r#"
702fn main() {
9c376795 703 let () = return;
353b0b11 704 //^^^^^^<never-to-any>
9c376795
FG
705 let (): () = return;
706 //^^^^^^<never-to-any>
707}
708 "#,
709 )
710 }
711}