Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
| -rw-r--r-- | crates/ide/src/inlay_hints.rs | 78 |
1 files changed, 69 insertions, 9 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 565bee88f3..ef1c155143 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -19,6 +19,7 @@ pub struct InlayHintsConfig { pub type_hints: bool, pub parameter_hints: bool, pub chaining_hints: bool, + pub reborrow_hints: bool, pub closure_return_type_hints: bool, pub lifetime_elision_hints: LifetimeElisionHints, pub param_names_for_lifetime_elision_hints: bool, @@ -35,6 +36,7 @@ pub enum LifetimeElisionHints { #[derive(Clone, Debug, PartialEq, Eq)] pub enum InlayKind { + ImplicitReborrow, TypeHint, ParameterHint, ClosureReturnTypeHint, @@ -116,17 +118,16 @@ fn hints( if let Some(expr) = ast::Expr::cast(node.clone()) { chaining_hints(hints, sema, &famous_defs, config, &expr); match expr { - ast::Expr::CallExpr(it) => { - param_name_hints(hints, sema, config, ast::Expr::from(it)); - } + ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { - param_name_hints(hints, sema, config, ast::Expr::from(it)); - } - ast::Expr::ClosureExpr(it) => { - closure_ret_hints(hints, sema, &famous_defs, config, it); + param_name_hints(hints, sema, config, ast::Expr::from(it)) } - _ => (), - } + ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, it), + // We could show reborrows for all expressions, but usually that is just noise to the user + // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it + ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr), + _ => None, + }; } else if let Some(it) = ast::IdentPat::cast(node.clone()) { bind_pat_hints(hints, sema, config, &it); } else if let Some(it) = ast::Fn::cast(node) { @@ -365,6 +366,28 @@ fn closure_ret_hints( Some(()) } +fn reborrow_hints( + acc: &mut Vec<InlayHint>, + sema: &Semantics<RootDatabase>, + config: &InlayHintsConfig, + expr: &ast::Expr, +) -> Option<()> { + if !config.reborrow_hints { + return None; + } + + let mutability = sema.is_implicit_reborrow(expr)?; + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::ImplicitReborrow, + label: match mutability { + hir::Mutability::Shared => SmolStr::new_inline("&*"), + hir::Mutability::Mut => SmolStr::new_inline("&mut *"), + }, + }); + Some(()) +} + fn chaining_hints( acc: &mut Vec<InlayHint>, sema: &Semantics<RootDatabase>, @@ -834,6 +857,7 @@ mod tests { lifetime_elision_hints: LifetimeElisionHints::Never, hide_named_constructor_hints: false, closure_return_type_hints: false, + reborrow_hints: false, param_names_for_lifetime_elision_hints: false, max_length: None, }; @@ -841,6 +865,7 @@ mod tests { type_hints: true, parameter_hints: true, chaining_hints: true, + reborrow_hints: true, closure_return_type_hints: true, lifetime_elision_hints: LifetimeElisionHints::Always, ..DISABLED_CONFIG @@ -2118,4 +2143,39 @@ impl () { "#, ); } + + #[test] + fn hints_implicit_reborrow() { + check_with_config( + InlayHintsConfig { reborrow_hints: true, ..DISABLED_CONFIG }, + r#" +fn __() { + let unique = &mut (); + let r_mov = unique; + let foo: &mut _ = unique; + //^^^^^^ &mut * + ref_mut_id(unique); + //^^^^^^ &mut * + let shared = ref_id(unique); + //^^^^^^ &* + let mov = shared; + let r_mov: &_ = shared; + ref_id(shared); + + identity(unique); + identity(shared); +} +fn identity<T>(t: T) -> T { + t +} +fn ref_mut_id(x: &mut ()) -> &mut () { + x + //^ &mut * +} +fn ref_id(x: &()) -> &() { + x +} +"#, + ); + } } |