1 //! Implementation of "adjustment" inlay hints:
3 //! let _: u32 = /* <never-to-any> */ loop {};
4 //! let _: &u32 = /* &* */ &mut 0;
6 use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
7 use ide_db::RootDatabase;
9 use syntax::ast::{self, AstNode};
11 use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
14 acc: &mut Vec<InlayHint>,
15 sema: &Semantics<'_, RootDatabase>,
16 config: &InlayHintsConfig,
19 if config.adjustment_hints == AdjustmentHints::Never {
23 // These inherit from the inner expression which would result in duplicate hints
24 if let ast::Expr::ParenExpr(_)
25 | ast::Expr::IfExpr(_)
26 | ast::Expr::BlockExpr(_)
27 | ast::Expr::MatchExpr(_) = expr
32 let parent = expr.syntax().parent().and_then(ast::Expr::cast);
33 let descended = sema.descend_node_into_attributes(expr.clone()).pop();
34 let desc_expr = descended.as_ref().unwrap_or(expr);
35 let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
36 let needs_parens = match parent {
39 ast::Expr::AwaitExpr(_)
40 | ast::Expr::CallExpr(_)
41 | ast::Expr::CastExpr(_)
42 | ast::Expr::FieldExpr(_)
43 | ast::Expr::MethodCallExpr(_)
44 | ast::Expr::TryExpr(_) => true,
45 // FIXME: shorthands need special casing, though not sure if adjustments are even valid there
46 ast::Expr::RecordExpr(_) => false,
47 ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr),
55 range: expr.syntax().text_range(),
56 kind: InlayKind::OpeningParenthesis,
61 for adjustment in adjustments.into_iter().rev() {
62 if adjustment.source == adjustment.target {
66 // FIXME: Add some nicer tooltips to each of these
67 let text = match adjustment.kind {
68 Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
71 Adjust::Deref(None) => "*",
72 Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*",
73 Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*",
74 Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => "&",
75 Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => "&mut ",
76 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => "&raw const ",
77 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ",
78 // some of these could be represented via `as` casts, but that's not too nice and
79 // handling everything as a prefix expr makes the `(` and `)` insertion easier
80 Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
82 PointerCast::ReifyFnPointer => "<fn-item-to-fn-pointer>",
83 PointerCast::UnsafeFnPointer => "<safe-fn-pointer-to-unsafe-fn-pointer>",
84 PointerCast::ClosureFnPointer(Safety::Unsafe) => {
85 "<closure-to-unsafe-fn-pointer>"
87 PointerCast::ClosureFnPointer(Safety::Safe) => "<closure-to-fn-pointer>",
88 PointerCast::MutToConstPointer => "<mut-ptr-to-const-ptr>",
89 PointerCast::ArrayToPointer => "<array-ptr-to-element-ptr>",
90 PointerCast::Unsize => "<unsize>",
96 range: expr.syntax().text_range(),
97 kind: InlayKind::AdjustmentHint,
104 range: expr.syntax().text_range(),
105 kind: InlayKind::ClosingParenthesis,
116 inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
117 AdjustmentHints, InlayHintsConfig,
121 fn adjustment_hints() {
123 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
125 //- minicore: coerce_unsized
127 let _: u32 = loop {};
128 //^^^^^^^<never-to-any>
129 let _: &u32 = &mut 0;
132 let _: &mut u32 = &mut 0;
135 let _: *const u32 = &mut 0;
138 let _: *mut u32 = &mut 0;
142 //^^^^<fn-item-to-fn-pointer>
143 let _: unsafe fn() = main;
144 //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
145 //^^^^<fn-item-to-fn-pointer>
146 let _: unsafe fn() = main as fn();
147 //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
149 //^^^^^<closure-to-fn-pointer>
150 let _: unsafe fn() = || {};
151 //^^^^^<closure-to-unsafe-fn-pointer>
152 let _: *const u32 = &mut 0u32 as *mut u32;
153 //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
154 let _: &mut [_] = &mut [0; 0];
155 //^^^^^^^^^^^<unsize>
173 (&mut Struct).consume();
175 (&mut Struct).by_ref();
178 (&mut Struct).by_ref_mut();
180 // Check that block-like expressions don't duplicate hints
181 let _: &mut [u32] = (&mut []);
185 let _: &mut [u32] = { &mut [] };
189 let _: &mut [u32] = unsafe { &mut [] };
193 let _: &mut [u32] = if true {
200 //^^^^^^^<never-to-any>
202 let _: &mut [u32] = match () { () => &mut [] }
208 #[derive(Copy, Clone)]
213 fn by_ref_mut(&mut self) {}
216 impl Trait for Struct {}
222 fn never_to_never_is_never_shown() {
224 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
231 let () = () else { return };